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/webui/jstemplate_builder.h"
     40 #include "ui/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 kErrorPuk[] = "incorrectPuk";
     67 const char kErrorOk[] = "ok";
     68 
     69 chromeos::NetworkDeviceHandler* GetNetworkDeviceHandler() {
     70   return chromeos::NetworkHandler::Get()->network_device_handler();
     71 }
     72 
     73 chromeos::NetworkStateHandler* GetNetworkStateHandler() {
     74   return chromeos::NetworkHandler::Get()->network_state_handler();
     75 }
     76 
     77 }  // namespace
     78 
     79 namespace chromeos {
     80 
     81 class SimUnlockUIHTMLSource : public content::URLDataSource {
     82  public:
     83   SimUnlockUIHTMLSource();
     84 
     85   // content::URLDataSource implementation.
     86   virtual std::string GetSource() const OVERRIDE;
     87   virtual void StartDataRequest(
     88       const std::string& path,
     89       int render_process_id,
     90       int render_view_id,
     91       const content::URLDataSource::GotDataCallback& callback) OVERRIDE;
     92   virtual std::string GetMimeType(const std::string&) const OVERRIDE {
     93     return "text/html";
     94   }
     95   virtual bool ShouldAddContentSecurityPolicy() const OVERRIDE {
     96     return false;
     97   }
     98 
     99  private:
    100   virtual ~SimUnlockUIHTMLSource() {}
    101 
    102   std::string service_path_;
    103   DISALLOW_COPY_AND_ASSIGN(SimUnlockUIHTMLSource);
    104 };
    105 
    106 // The handler for Javascript messages related to the "sim-unlock" view.
    107 class SimUnlockHandler : public WebUIMessageHandler,
    108                          public base::SupportsWeakPtr<SimUnlockHandler>,
    109                          public NetworkStateHandlerObserver {
    110  public:
    111   SimUnlockHandler();
    112   virtual ~SimUnlockHandler();
    113 
    114   // WebUIMessageHandler implementation.
    115   virtual void RegisterMessages() OVERRIDE;
    116 
    117   // NetworkStateHandlerObserver implementation.
    118   virtual void DeviceListChanged() OVERRIDE;
    119 
    120  private:
    121   // Should keep this state enum in sync with similar one in JS code.
    122   // SIM_NOT_LOCKED_ASK_PIN - SIM card is not locked but we ask user
    123   // for PIN input because PinRequired preference change was requested.
    124   // SIM_NOT_LOCKED_CHANGE_PIN - SIM card is not locked, ask user for old PIN
    125   // and new PIN to change it.
    126   typedef enum SimUnlockState {
    127     SIM_UNLOCK_LOADING           = -1,
    128     SIM_ABSENT_NOT_LOCKED        =  0,
    129     SIM_NOT_LOCKED_ASK_PIN       =  1,
    130     SIM_NOT_LOCKED_CHANGE_PIN    =  2,
    131     SIM_LOCKED_PIN               =  3,
    132     SIM_LOCKED_NO_PIN_TRIES_LEFT =  4,
    133     SIM_LOCKED_PUK               =  5,
    134     SIM_LOCKED_NO_PUK_TRIES_LEFT =  6,
    135     SIM_DISABLED                 =  7,
    136   } SimUnlockState;
    137 
    138   // Type of the SIM unlock code.
    139   enum SimUnlockCode {
    140     CODE_PIN,
    141     CODE_PUK
    142   };
    143 
    144   enum PinOperationError {
    145     PIN_ERROR_NONE = 0,
    146     PIN_ERROR_UNKNOWN = 1,
    147     PIN_ERROR_INCORRECT_CODE = 2,
    148     PIN_ERROR_BLOCKED = 3
    149   };
    150 
    151   class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> {
    152    public:
    153     explicit TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler)
    154         : handler_(handler),
    155           code_type_() {
    156     }
    157 
    158     TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler,
    159               const std::string& code,
    160               SimUnlockCode code_type)
    161         : handler_(handler),
    162           code_(code),
    163           code_type_(code_type) {
    164     }
    165 
    166     void HandleCancel() {
    167       if (handler_)
    168         handler_->CancelDialog();
    169     }
    170 
    171     void HandleEnterCode() {
    172       if (handler_)
    173         handler_->EnterCode(code_, code_type_);
    174     }
    175 
    176     void HandleInitialize() {
    177       if (handler_)
    178         handler_->InitializeSimStatus();
    179     }
    180 
    181     void HandleProceedToPukInput() {
    182       if (handler_)
    183         handler_->ProceedToPukInput();
    184     }
    185 
    186    private:
    187     friend class base::RefCountedThreadSafe<TaskProxy>;
    188 
    189     ~TaskProxy() {}
    190 
    191     base::WeakPtr<SimUnlockHandler> handler_;
    192 
    193     // Pending code input (PIN/PUK).
    194     std::string code_;
    195 
    196     // Pending code type.
    197     SimUnlockCode code_type_;
    198 
    199     DISALLOW_COPY_AND_ASSIGN(TaskProxy);
    200   };
    201 
    202   // Returns the cellular device that this dialog currently corresponds to.
    203   const DeviceState* GetCellularDevice();
    204 
    205   // Processing for the cases when dialog was cancelled.
    206   void CancelDialog();
    207 
    208   // Pass PIN/PUK code to shill and check status.
    209   void EnterCode(const std::string& code, SimUnlockCode code_type);
    210 
    211   // Methods to invoke shill PIN/PUK D-Bus operations.
    212   void ChangeRequirePin(bool require_pin, const std::string& pin);
    213   void EnterPin(const std::string& pin);
    214   void ChangePin(const std::string& old_pin, const std::string& new_pin);
    215   void UnblockPin(const std::string& puk, const std::string& new_pin);
    216   void PinOperationSuccessCallback(const std::string& operation_name);
    217   void PinOperationErrorCallback(const std::string& operation_name,
    218                                  const std::string& error_name,
    219                                  scoped_ptr<base::DictionaryValue> error_data);
    220 
    221   // Called when an asynchronous PIN operation has completed.
    222   void OnPinOperationCompleted(PinOperationError error);
    223 
    224   // Single handler for PIN/PUK code operations.
    225   void HandleEnterCode(SimUnlockCode code_type, const std::string& code);
    226 
    227   // Handlers for JS WebUI messages.
    228   void HandleCancel(const ListValue* args);
    229   void HandleChangePinCode(const ListValue* args);
    230   void HandleEnterPinCode(const ListValue* args);
    231   void HandleEnterPukCode(const ListValue* args);
    232   void HandleProceedToPukInput(const ListValue* args);
    233   void HandleSimStatusInitialize(const ListValue* args);
    234 
    235   // Initialize current SIM card status, passes that to page.
    236   void InitializeSimStatus();
    237 
    238   // Notifies SIM Security tab handler that RequirePin preference change
    239   // has been ended (either updated or cancelled).
    240   void NotifyOnRequirePinChangeEnded(bool new_value);
    241 
    242   // Notifies observers that the EnterPin or EnterPuk dialog has been
    243   // completed (either cancelled or with entry of PIN/PUK).
    244   void NotifyOnEnterPinEnded(bool cancelled);
    245 
    246   // Checks whether SIM card is in PUK locked state and proceeds to PUK input.
    247   void ProceedToPukInput();
    248 
    249   // Processes current SIM card state and update internal state/page.
    250   void ProcessSimCardState(const DeviceState* cellular);
    251 
    252   // Updates page with the current state/SIM card info/error.
    253   void UpdatePage(const DeviceState* cellular, const std::string& error_msg);
    254 
    255   // Dialog internal state.
    256   SimUnlockState state_;
    257 
    258   // Path of the Cellular device that we monitor property updates from.
    259   std::string cellular_device_path_;
    260 
    261   // Type of the dialog: generic unlock/change pin/change PinRequire.
    262   SimDialogDelegate::SimDialogMode dialog_mode_;
    263 
    264   // New PIN value for the case when we unblock SIM card or change PIN.
    265   std::string new_pin_;
    266 
    267   // The initial lock type value, used to observe changes to lock status;
    268   std::string sim_lock_type_;
    269 
    270   // True if there's a pending PIN operation.
    271   // That means that SIM lock state change will be received 2 times:
    272   // OnNetworkDeviceSimLockChanged and OnPinOperationCompleted.
    273   // First one should be ignored.
    274   bool pending_pin_operation_;
    275 
    276   base::WeakPtrFactory<SimUnlockHandler> weak_ptr_factory_;
    277 
    278   DISALLOW_COPY_AND_ASSIGN(SimUnlockHandler);
    279 };
    280 
    281 // SimUnlockUIHTMLSource -------------------------------------------------------
    282 
    283 SimUnlockUIHTMLSource::SimUnlockUIHTMLSource() {
    284 }
    285 
    286 std::string SimUnlockUIHTMLSource::GetSource() const {
    287   return chrome::kChromeUISimUnlockHost;
    288 }
    289 
    290 void SimUnlockUIHTMLSource::StartDataRequest(
    291     const std::string& path,
    292     int render_process_id,
    293     int render_view_id,
    294     const content::URLDataSource::GotDataCallback& callback) {
    295   DictionaryValue strings;
    296   strings.SetString("title",
    297       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TITLE));
    298   strings.SetString("ok", l10n_util::GetStringUTF16(IDS_OK));
    299   strings.SetString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL));
    300   strings.SetString("enterPinTitle",
    301       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TITLE));
    302   strings.SetString("enterPinMessage",
    303       l10n_util::GetStringUTF16(IDS_SIM_ENTER_PIN_MESSAGE));
    304   strings.SetString("enterPinTriesMessage",
    305       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TRIES_MESSAGE));
    306   strings.SetString("incorrectPinTriesMessage",
    307       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_INCORRECT_PIN_TRIES_MESSAGE));
    308   strings.SetString("incorrectPinTitle",
    309       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_INCORRECT_PIN_TITLE));
    310   // TODO(nkostylev): Pass carrier name if we know that.
    311   strings.SetString("noPinTriesLeft", l10n_util::GetStringFUTF16(
    312       IDS_SIM_UNLOCK_NO_PIN_TRIES_LEFT_MESSAGE,
    313       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_DEFAULT_CARRIER)));
    314   strings.SetString("enterPukButton",
    315       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_BUTTON));
    316   strings.SetString("enterPukTitle",
    317       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_TITLE));
    318   strings.SetString("enterPukWarning",
    319       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_WARNING));
    320   // TODO(nkostylev): Pass carrier name if we know that.
    321   strings.SetString("enterPukMessage", l10n_util::GetStringFUTF16(
    322       IDS_SIM_UNLOCK_ENTER_PUK_MESSAGE,
    323       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_DEFAULT_CARRIER)));
    324   strings.SetString("choosePinTitle",
    325       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_CHOOSE_PIN_TITLE));
    326   strings.SetString("choosePinMessage",
    327       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_CHOOSE_PIN_MESSAGE));
    328   strings.SetString("newPin", l10n_util::GetStringUTF16(
    329       IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_NEW_PIN));
    330   strings.SetString("retypeNewPin", l10n_util::GetStringUTF16(
    331       IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_RETYPE_PIN));
    332   strings.SetString("pinsDontMatchMessage", l10n_util::GetStringUTF16(
    333       IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_PINS_DONT_MATCH_ERROR));
    334   strings.SetString("noPukTriesLeft",
    335       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_NO_PUK_TRIES_LEFT_MESSAGE));
    336   strings.SetString("simDisabledTitle",
    337       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_SIM_DISABLED_TITLE));
    338   strings.SetString("simDisabledMessage",
    339       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_SIM_DISABLED_MESSAGE));
    340 
    341   strings.SetString("changePinTitle", l10n_util::GetStringUTF16(
    342       IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_TITLE));
    343   strings.SetString("changePinMessage", l10n_util::GetStringUTF16(
    344       IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_MESSAGE));
    345   strings.SetString("oldPin", l10n_util::GetStringUTF16(
    346       IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_OLD_PIN));
    347 
    348   webui::SetFontAndTextDirection(&strings);
    349 
    350   static const base::StringPiece html(
    351       ResourceBundle::GetSharedInstance().GetRawDataResource(
    352           IDR_SIM_UNLOCK_HTML));
    353 
    354   std::string full_html = webui::GetI18nTemplateHtml(html, &strings);
    355 
    356   callback.Run(base::RefCountedString::TakeString(&full_html));
    357 }
    358 
    359 // SimUnlockHandler ------------------------------------------------------------
    360 
    361 SimUnlockHandler::SimUnlockHandler()
    362     : state_(SIM_UNLOCK_LOADING),
    363       dialog_mode_(SimDialogDelegate::SIM_DIALOG_UNLOCK),
    364       pending_pin_operation_(false),
    365       weak_ptr_factory_(this) {
    366   if (GetNetworkStateHandler()->GetTechnologyState(flimflam::kTypeCellular)
    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(BrowserThread::CurrentlyOn(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 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 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 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 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 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 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(BrowserThread::CurrentlyOn(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 = GetNetworkStateHandler()->
    710       GetDeviceStateByType(flimflam::kTypeCellular);
    711   if (cellular_device) {
    712     cellular_device_path_ = cellular_device->path();
    713     sim_lock_type_ = cellular_device->sim_lock_type();
    714   }
    715   ProcessSimCardState(cellular_device);
    716 }
    717 
    718 void SimUnlockHandler::ProceedToPukInput() {
    719   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    720   ProcessSimCardState(GetCellularDevice());
    721 }
    722 
    723 void SimUnlockHandler::ProcessSimCardState(
    724     const DeviceState* cellular) {
    725   std::string error_msg;
    726   if (cellular) {
    727     uint32 retries_left = cellular->sim_retries_left();
    728     VLOG(1) << "Current state: " << state_ << " lock_type: " << sim_lock_type_
    729             << " retries: " << retries_left;
    730     switch (state_) {
    731       case SIM_UNLOCK_LOADING:
    732         if (sim_lock_type_ == flimflam::kSIMLockPin) {
    733           state_ = SIM_LOCKED_PIN;
    734         } else if (sim_lock_type_ == flimflam::kSIMLockPuk) {
    735           if (retries_left > 0)
    736             state_ = SIM_LOCKED_PUK;
    737           else
    738             state_ = SIM_DISABLED;
    739         } else if (sim_lock_type_.empty()) {
    740           if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON ||
    741               dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) {
    742             state_ = SIM_NOT_LOCKED_ASK_PIN;
    743           } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN) {
    744             state_ = SIM_NOT_LOCKED_CHANGE_PIN;
    745           } else {
    746             state_ = SIM_ABSENT_NOT_LOCKED;
    747           }
    748         } else {
    749           // SIM_UNKNOWN: when SIM status is not initialized (should not happen,
    750           // since this UI is accessible when SIM is initialized)
    751           // or SIM card is absent. In latter case just close dialog.
    752           state_ = SIM_ABSENT_NOT_LOCKED;
    753         }
    754         break;
    755       case SIM_ABSENT_NOT_LOCKED:
    756         // Dialog will close itself in this case.
    757         break;
    758       case SIM_NOT_LOCKED_ASK_PIN:
    759       case SIM_NOT_LOCKED_CHANGE_PIN:
    760         // We always start in these states when SIM is unlocked.
    761         // So if we get here while still being UNLOCKED,
    762         // that means entered PIN was incorrect.
    763         if (sim_lock_type_.empty()) {
    764           error_msg = kErrorPin;
    765         } else if (sim_lock_type_ == flimflam::kSIMLockPuk) {
    766           state_ = SIM_LOCKED_NO_PIN_TRIES_LEFT;
    767         } else {
    768           NOTREACHED()
    769               << "Change PIN / Set lock mode with unexpected SIM lock state";
    770           state_ = SIM_ABSENT_NOT_LOCKED;
    771         }
    772         break;
    773       case SIM_LOCKED_PIN:
    774         if (sim_lock_type_ == flimflam::kSIMLockPuk) {
    775           state_ = SIM_LOCKED_NO_PIN_TRIES_LEFT;
    776         } else if (sim_lock_type_ == flimflam::kSIMLockPin) {
    777           // Still locked with PIN.
    778           error_msg = kErrorPin;
    779         } else {
    780           state_ = SIM_ABSENT_NOT_LOCKED;
    781         }
    782         break;
    783       case SIM_LOCKED_NO_PIN_TRIES_LEFT:
    784         // Proceed user to PUK input.
    785         state_ = SIM_LOCKED_PUK;
    786         break;
    787       case SIM_LOCKED_PUK:
    788         if (sim_lock_type_ != flimflam::kSIMLockPin &&
    789             sim_lock_type_ != flimflam::kSIMLockPuk) {
    790           state_ = SIM_ABSENT_NOT_LOCKED;
    791         } else if (retries_left == 0) {
    792           state_ = SIM_LOCKED_NO_PUK_TRIES_LEFT;
    793         }
    794         // Otherwise SIM card is still locked with PUK code.
    795         // Dialog will display enter PUK screen with an updated retries count.
    796         break;
    797       case SIM_LOCKED_NO_PUK_TRIES_LEFT:
    798       case SIM_DISABLED:
    799         // User will close dialog manually.
    800         break;
    801     }
    802   } else {
    803     VLOG(1) << "Cellular device is absent.";
    804     // No cellular device, should close dialog.
    805     state_ = SIM_ABSENT_NOT_LOCKED;
    806   }
    807   VLOG(1) << "New state: " << state_;
    808   UpdatePage(cellular, error_msg);
    809 }
    810 
    811 void SimUnlockHandler::UpdatePage(const DeviceState* cellular,
    812                                   const std::string& error_msg) {
    813   DictionaryValue sim_dict;
    814   if (cellular)
    815     sim_dict.SetInteger(kTriesLeft, cellular->sim_retries_left());
    816   sim_dict.SetInteger(kState, state_);
    817   if (!error_msg.empty())
    818     sim_dict.SetString(kError, error_msg);
    819   else
    820     sim_dict.SetString(kError, kErrorOk);
    821   web_ui()->CallJavascriptFunction(kJsApiSimStatusChanged, sim_dict);
    822 }
    823 
    824 // SimUnlockUI -----------------------------------------------------------------
    825 
    826 SimUnlockUI::SimUnlockUI(content::WebUI* web_ui) : WebUIController(web_ui) {
    827   SimUnlockHandler* handler = new SimUnlockHandler();
    828   web_ui->AddMessageHandler(handler);
    829   SimUnlockUIHTMLSource* html_source = new SimUnlockUIHTMLSource();
    830 
    831   // Set up the chrome://sim-unlock/ source.
    832   Profile* profile = Profile::FromWebUI(web_ui);
    833   content::URLDataSource::Add(profile, html_source);
    834 }
    835 
    836 }  // namespace chromeos
    837