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/mobile_setup_ui.h"
      6 
      7 #include <algorithm>
      8 #include <map>
      9 #include <string>
     10 
     11 #include "base/bind.h"
     12 #include "base/bind_helpers.h"
     13 #include "base/json/json_writer.h"
     14 #include "base/logging.h"
     15 #include "base/memory/ref_counted_memory.h"
     16 #include "base/memory/weak_ptr.h"
     17 #include "base/message_loop/message_loop.h"
     18 #include "base/metrics/histogram.h"
     19 #include "base/strings/string_piece.h"
     20 #include "base/strings/string_util.h"
     21 #include "base/strings/utf_string_conversions.h"
     22 #include "base/values.h"
     23 #include "chrome/browser/chromeos/mobile/mobile_activator.h"
     24 #include "chrome/browser/profiles/profile.h"
     25 #include "chrome/browser/ui/browser_list.h"
     26 #include "chrome/common/pref_names.h"
     27 #include "chrome/common/render_messages.h"
     28 #include "chrome/common/url_constants.h"
     29 #include "chromeos/network/device_state.h"
     30 #include "chromeos/network/network_configuration_handler.h"
     31 #include "chromeos/network/network_event_log.h"
     32 #include "chromeos/network/network_state.h"
     33 #include "chromeos/network/network_state_handler.h"
     34 #include "chromeos/network/network_state_handler_observer.h"
     35 #include "content/public/browser/browser_thread.h"
     36 #include "content/public/browser/url_data_source.h"
     37 #include "content/public/browser/web_contents.h"
     38 #include "content/public/browser/web_ui.h"
     39 #include "content/public/browser/web_ui_message_handler.h"
     40 #include "grit/browser_resources.h"
     41 #include "grit/chromium_strings.h"
     42 #include "grit/generated_resources.h"
     43 #include "grit/locale_settings.h"
     44 #include "third_party/cros_system_api/dbus/service_constants.h"
     45 #include "ui/base/l10n/l10n_util.h"
     46 #include "ui/base/resource/resource_bundle.h"
     47 #include "ui/base/webui/jstemplate_builder.h"
     48 #include "ui/base/webui/web_ui_util.h"
     49 #include "url/gurl.h"
     50 
     51 using chromeos::MobileActivator;
     52 using chromeos::NetworkHandler;
     53 using chromeos::NetworkState;
     54 using content::BrowserThread;
     55 using content::RenderViewHost;
     56 using content::WebContents;
     57 using content::WebUIMessageHandler;
     58 
     59 namespace {
     60 
     61 // Host page JS API function names.
     62 const char kJsApiStartActivation[] = "startActivation";
     63 const char kJsApiSetTransactionStatus[] = "setTransactionStatus";
     64 const char kJsApiPaymentPortalLoad[] = "paymentPortalLoad";
     65 const char kJsGetDeviceInfo[] = "getDeviceInfo";
     66 const char kJsApiResultOK[] = "ok";
     67 
     68 const char kJsDeviceStatusChangedCallback[] =
     69     "mobile.MobileSetup.deviceStateChanged";
     70 const char kJsPortalFrameLoadFailedCallback[] =
     71     "mobile.MobileSetup.portalFrameLoadError";
     72 const char kJsPortalFrameLoadCompletedCallback[] =
     73     "mobile.MobileSetup.portalFrameLoadCompleted";
     74 const char kJsGetDeviceInfoCallback[] =
     75     "mobile.MobileSetupPortal.onGotDeviceInfo";
     76 const char kJsConnectivityChangedCallback[] =
     77     "mobile.MobileSetupPortal.onConnectivityChanged";
     78 
     79 void DataRequestFailed(
     80     const std::string& service_path,
     81     const content::URLDataSource::GotDataCallback& callback) {
     82   NET_LOG_ERROR("Data Request Failed for Mobile Setup", service_path);
     83   scoped_refptr<base::RefCountedBytes> html_bytes(new base::RefCountedBytes);
     84   callback.Run(html_bytes.get());
     85 }
     86 
     87 // Converts the network properties into a JS object.
     88 void GetDeviceInfo(const DictionaryValue& properties, DictionaryValue* value) {
     89   std::string name;
     90   properties.GetStringWithoutPathExpansion(shill::kNameProperty, &name);
     91   bool activate_over_non_cellular_networks = false;
     92   properties.GetBooleanWithoutPathExpansion(
     93       shill::kActivateOverNonCellularNetworkProperty,
     94       &activate_over_non_cellular_networks);
     95   const DictionaryValue* payment_dict;
     96   std::string payment_url, post_method, post_data;
     97   if (properties.GetDictionaryWithoutPathExpansion(
     98           shill::kPaymentPortalProperty, &payment_dict)) {
     99     payment_dict->GetStringWithoutPathExpansion(
    100         shill::kPaymentPortalURL, &payment_url);
    101     payment_dict->GetStringWithoutPathExpansion(
    102         shill::kPaymentPortalMethod, &post_method);
    103     payment_dict->GetStringWithoutPathExpansion(
    104         shill::kPaymentPortalPostData, &post_data);
    105   }
    106 
    107   value->SetBoolean("activate_over_non_cellular_network",
    108                     activate_over_non_cellular_networks);
    109   value->SetString("carrier", name);
    110   value->SetString("payment_url", payment_url);
    111   if (LowerCaseEqualsASCII(post_method, "post") && !post_data.empty())
    112     value->SetString("post_data", post_data);
    113 
    114   // Use the cached DeviceState properties.
    115   std::string device_path;
    116   if (!properties.GetStringWithoutPathExpansion(
    117           shill::kDeviceProperty, &device_path) ||
    118       device_path.empty()) {
    119     return;
    120   }
    121   const chromeos::DeviceState* device =
    122       NetworkHandler::Get()->network_state_handler()->GetDeviceState(
    123           device_path);
    124   if (!device)
    125     return;
    126 
    127   value->SetString("MEID", device->meid());
    128   value->SetString("IMEI", device->imei());
    129   value->SetString("MDN", device->mdn());
    130 }
    131 
    132 void SetActivationStateAndError(MobileActivator::PlanActivationState state,
    133                                 const std::string& error_description,
    134                                 DictionaryValue* value) {
    135   value->SetInteger("state", state);
    136   if (!error_description.empty())
    137     value->SetString("error", error_description);
    138 }
    139 
    140 }  // namespace
    141 
    142 class MobileSetupUIHTMLSource : public content::URLDataSource {
    143  public:
    144   MobileSetupUIHTMLSource();
    145 
    146   // content::URLDataSource implementation.
    147   virtual std::string GetSource() const OVERRIDE;
    148   virtual void StartDataRequest(
    149       const std::string& path,
    150       int render_process_id,
    151       int render_view_id,
    152       const content::URLDataSource::GotDataCallback& callback) OVERRIDE;
    153   virtual std::string GetMimeType(const std::string&) const OVERRIDE {
    154     return "text/html";
    155   }
    156   virtual bool ShouldAddContentSecurityPolicy() const OVERRIDE {
    157     return false;
    158   }
    159 
    160  private:
    161   virtual ~MobileSetupUIHTMLSource() {}
    162 
    163   void GetPropertiesAndStartDataRequest(
    164       const content::URLDataSource::GotDataCallback& callback,
    165       const std::string& service_path,
    166       const base::DictionaryValue& properties);
    167   void GetPropertiesFailure(
    168       const content::URLDataSource::GotDataCallback& callback,
    169       const std::string& service_path,
    170       const std::string& error_name,
    171       scoped_ptr<base::DictionaryValue> error_data);
    172 
    173   base::WeakPtrFactory<MobileSetupUIHTMLSource> weak_ptr_factory_;
    174 
    175   DISALLOW_COPY_AND_ASSIGN(MobileSetupUIHTMLSource);
    176 };
    177 
    178 // The handler for Javascript messages related to the "register" view.
    179 class MobileSetupHandler
    180   : public WebUIMessageHandler,
    181     public MobileActivator::Observer,
    182     public chromeos::NetworkStateHandlerObserver,
    183     public base::SupportsWeakPtr<MobileSetupHandler> {
    184  public:
    185   MobileSetupHandler();
    186   virtual ~MobileSetupHandler();
    187 
    188   // WebUIMessageHandler implementation.
    189   virtual void RegisterMessages() OVERRIDE;
    190 
    191  private:
    192   enum Type {
    193     TYPE_UNDETERMINED,
    194     // The network is not yet activated, and the webui is in activation flow.
    195     TYPE_ACTIVATION,
    196     // The network is activated, the webui displays network portal.
    197     TYPE_PORTAL,
    198     // Same as TYPE_PORTAL, but the network technology is LTE. The webui is
    199     // additionally aware of network manager state and whether the portal can be
    200     // reached.
    201     TYPE_PORTAL_LTE
    202   };
    203 
    204   // MobileActivator::Observer.
    205   virtual void OnActivationStateChanged(
    206       const NetworkState* network,
    207       MobileActivator::PlanActivationState new_state,
    208       const std::string& error_description) OVERRIDE;
    209 
    210   // Callbacks for NetworkConfigurationHandler::GetProperties.
    211   void GetPropertiesAndCallStatusChanged(
    212       MobileActivator::PlanActivationState state,
    213       const std::string& error_description,
    214       const std::string& service_path,
    215       const base::DictionaryValue& properties);
    216   void GetPropertiesAndCallGetDeviceInfo(
    217       const std::string& service_path,
    218       const base::DictionaryValue& properties);
    219   void GetPropertiesFailure(
    220       const std::string& service_path,
    221       const std::string& callback_name,
    222       const std::string& error_name,
    223       scoped_ptr<base::DictionaryValue> error_data);
    224 
    225   // Handlers for JS WebUI messages.
    226   void HandleSetTransactionStatus(const ListValue* args);
    227   void HandleStartActivation(const ListValue* args);
    228   void HandlePaymentPortalLoad(const ListValue* args);
    229   void HandleGetDeviceInfo(const ListValue* args);
    230 
    231   // NetworkStateHandlerObserver implementation.
    232   virtual void NetworkConnectionStateChanged(
    233       const NetworkState* network) OVERRIDE;
    234   virtual void DefaultNetworkChanged(
    235       const NetworkState* default_network) OVERRIDE;
    236 
    237   // Updates |lte_portal_reachable_| for lte network |network| and notifies
    238   // webui of the new state if the reachability changed or |force_notification|
    239   // is set.
    240   void UpdatePortalReachability(const NetworkState* network,
    241                                 bool force_notification);
    242 
    243   // Sends message to host registration page with system/user info data.
    244   void SendDeviceInfo();
    245 
    246   // Type of the mobilesetup webui deduced from received messages.
    247   Type type_;
    248   // Whether portal page for lte networks can be reached in current network
    249   // connection state. This value is reflected in portal webui for lte networks.
    250   // Initial value is true.
    251   bool lte_portal_reachable_;
    252   base::WeakPtrFactory<MobileSetupHandler> weak_ptr_factory_;
    253 
    254   DISALLOW_COPY_AND_ASSIGN(MobileSetupHandler);
    255 };
    256 
    257 ////////////////////////////////////////////////////////////////////////////////
    258 //
    259 // MobileSetupUIHTMLSource
    260 //
    261 ////////////////////////////////////////////////////////////////////////////////
    262 
    263 MobileSetupUIHTMLSource::MobileSetupUIHTMLSource()
    264     : weak_ptr_factory_(this) {
    265 }
    266 
    267 std::string MobileSetupUIHTMLSource::GetSource() const {
    268   return chrome::kChromeUIMobileSetupHost;
    269 }
    270 
    271 void MobileSetupUIHTMLSource::StartDataRequest(
    272     const std::string& path,
    273     int render_process_id,
    274     int render_view_id,
    275     const content::URLDataSource::GotDataCallback& callback) {
    276   NetworkHandler::Get()->network_configuration_handler()->GetProperties(
    277       path,
    278       base::Bind(&MobileSetupUIHTMLSource::GetPropertiesAndStartDataRequest,
    279                  weak_ptr_factory_.GetWeakPtr(),
    280                  callback),
    281       base::Bind(&MobileSetupUIHTMLSource::GetPropertiesFailure,
    282                  weak_ptr_factory_.GetWeakPtr(),
    283                  callback, path));
    284 }
    285 
    286 void MobileSetupUIHTMLSource::GetPropertiesAndStartDataRequest(
    287     const content::URLDataSource::GotDataCallback& callback,
    288     const std::string& service_path,
    289     const base::DictionaryValue& properties) {
    290   const DictionaryValue* payment_dict;
    291   std::string name, usage_url, activation_state, payment_url;
    292   if (!properties.GetStringWithoutPathExpansion(
    293           shill::kNameProperty, &name) ||
    294       !properties.GetStringWithoutPathExpansion(
    295           shill::kUsageURLProperty, &usage_url) ||
    296       !properties.GetStringWithoutPathExpansion(
    297           shill::kActivationStateProperty, &activation_state) ||
    298       !properties.GetDictionaryWithoutPathExpansion(
    299           shill::kPaymentPortalProperty, &payment_dict) ||
    300       !payment_dict->GetStringWithoutPathExpansion(
    301           shill::kPaymentPortalURL, &payment_url)) {
    302     DataRequestFailed(service_path, callback);
    303     return;
    304   }
    305 
    306   if (payment_url.empty() && usage_url.empty() &&
    307       activation_state != shill::kActivationStateActivated) {
    308     DataRequestFailed(service_path, callback);
    309     return;
    310   }
    311 
    312   NET_LOG_EVENT("Starting mobile setup", service_path);
    313   DictionaryValue strings;
    314 
    315   strings.SetString("connecting_header",
    316                     l10n_util::GetStringFUTF16(IDS_MOBILE_CONNECTING_HEADER,
    317                                                UTF8ToUTF16(name)));
    318   strings.SetString("error_header",
    319                     l10n_util::GetStringUTF16(IDS_MOBILE_ERROR_HEADER));
    320   strings.SetString("activating_header",
    321                     l10n_util::GetStringUTF16(IDS_MOBILE_ACTIVATING_HEADER));
    322   strings.SetString("completed_header",
    323                     l10n_util::GetStringUTF16(IDS_MOBILE_COMPLETED_HEADER));
    324   strings.SetString("please_wait",
    325                     l10n_util::GetStringUTF16(IDS_MOBILE_PLEASE_WAIT));
    326   strings.SetString("completed_text",
    327                     l10n_util::GetStringUTF16(IDS_MOBILE_COMPLETED_TEXT));
    328   strings.SetString("portal_unreachable_header",
    329                     l10n_util::GetStringUTF16(IDS_MOBILE_NO_CONNECTION_HEADER));
    330   strings.SetString("invalid_device_info_header",
    331       l10n_util::GetStringUTF16(IDS_MOBILE_INVALID_DEVICE_INFO_HEADER));
    332   strings.SetString("title", l10n_util::GetStringUTF16(IDS_MOBILE_SETUP_TITLE));
    333   strings.SetString("close_button",
    334                     l10n_util::GetStringUTF16(IDS_CLOSE));
    335   strings.SetString("cancel_button",
    336                     l10n_util::GetStringUTF16(IDS_CANCEL));
    337   strings.SetString("ok_button",
    338                     l10n_util::GetStringUTF16(IDS_OK));
    339   webui::SetFontAndTextDirection(&strings);
    340 
    341   // The webui differs based on whether the network is activated or not. If the
    342   // network is activated, the webui goes straight to portal. Otherwise the
    343   // webui is used for activation flow.
    344   std::string full_html;
    345   if (activation_state == shill::kActivationStateActivated) {
    346     static const base::StringPiece html_for_activated(
    347         ResourceBundle::GetSharedInstance().GetRawDataResource(
    348             IDR_MOBILE_SETUP_PORTAL_PAGE_HTML));
    349     full_html = webui::GetI18nTemplateHtml(html_for_activated, &strings);
    350   } else {
    351     static const base::StringPiece html_for_non_activated(
    352         ResourceBundle::GetSharedInstance().GetRawDataResource(
    353             IDR_MOBILE_SETUP_PAGE_HTML));
    354     full_html = webui::GetI18nTemplateHtml(html_for_non_activated, &strings);
    355   }
    356 
    357   callback.Run(base::RefCountedString::TakeString(&full_html));
    358 }
    359 
    360 void MobileSetupUIHTMLSource::GetPropertiesFailure(
    361     const content::URLDataSource::GotDataCallback& callback,
    362     const std::string& service_path,
    363     const std::string& error_name,
    364     scoped_ptr<base::DictionaryValue> error_data) {
    365   DataRequestFailed(service_path, callback);
    366 }
    367 
    368 ////////////////////////////////////////////////////////////////////////////////
    369 //
    370 // MobileSetupHandler
    371 //
    372 ////////////////////////////////////////////////////////////////////////////////
    373 MobileSetupHandler::MobileSetupHandler()
    374     : type_(TYPE_UNDETERMINED),
    375       lte_portal_reachable_(true),
    376       weak_ptr_factory_(this) {
    377 }
    378 
    379 MobileSetupHandler::~MobileSetupHandler() {
    380   if (type_ == TYPE_ACTIVATION) {
    381     MobileActivator::GetInstance()->RemoveObserver(this);
    382     MobileActivator::GetInstance()->TerminateActivation();
    383   } else if (type_ == TYPE_PORTAL_LTE) {
    384     NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
    385                                                                    FROM_HERE);
    386   }
    387 }
    388 
    389 void MobileSetupHandler::OnActivationStateChanged(
    390     const NetworkState* network,
    391     MobileActivator::PlanActivationState state,
    392     const std::string& error_description) {
    393   DCHECK_EQ(TYPE_ACTIVATION, type_);
    394   if (!web_ui())
    395     return;
    396 
    397   if (!network) {
    398     DictionaryValue device_dict;
    399     SetActivationStateAndError(state, error_description, &device_dict);
    400     web_ui()->CallJavascriptFunction(kJsDeviceStatusChangedCallback,
    401                                      device_dict);
    402     return;
    403   }
    404 
    405   NetworkHandler::Get()->network_configuration_handler()->GetProperties(
    406       network->path(),
    407       base::Bind(&MobileSetupHandler::GetPropertiesAndCallStatusChanged,
    408                  weak_ptr_factory_.GetWeakPtr(),
    409                  state,
    410                  error_description),
    411       base::Bind(&MobileSetupHandler::GetPropertiesFailure,
    412                  weak_ptr_factory_.GetWeakPtr(),
    413                  network->path(),
    414                  kJsDeviceStatusChangedCallback));
    415 }
    416 
    417 void MobileSetupHandler::GetPropertiesAndCallStatusChanged(
    418     MobileActivator::PlanActivationState state,
    419     const std::string& error_description,
    420     const std::string& service_path,
    421     const base::DictionaryValue& properties) {
    422   DictionaryValue device_dict;
    423   GetDeviceInfo(properties, &device_dict);
    424   SetActivationStateAndError(state, error_description, &device_dict);
    425   web_ui()->CallJavascriptFunction(kJsDeviceStatusChangedCallback, device_dict);
    426 }
    427 
    428 void MobileSetupHandler::RegisterMessages() {
    429   web_ui()->RegisterMessageCallback(kJsApiStartActivation,
    430       base::Bind(&MobileSetupHandler::HandleStartActivation,
    431                  base::Unretained(this)));
    432   web_ui()->RegisterMessageCallback(kJsApiSetTransactionStatus,
    433       base::Bind(&MobileSetupHandler::HandleSetTransactionStatus,
    434                  base::Unretained(this)));
    435   web_ui()->RegisterMessageCallback(kJsApiPaymentPortalLoad,
    436       base::Bind(&MobileSetupHandler::HandlePaymentPortalLoad,
    437                  base::Unretained(this)));
    438   web_ui()->RegisterMessageCallback(kJsGetDeviceInfo,
    439       base::Bind(&MobileSetupHandler::HandleGetDeviceInfo,
    440                  base::Unretained(this)));
    441 }
    442 
    443 void MobileSetupHandler::HandleStartActivation(const ListValue* args) {
    444   DCHECK_EQ(TYPE_UNDETERMINED, type_);
    445 
    446   if (!web_ui())
    447     return;
    448 
    449   std::string path = web_ui()->GetWebContents()->GetURL().path();
    450   if (!path.size())
    451     return;
    452 
    453   LOG(WARNING) << "Starting activation for service " << path;
    454 
    455   type_ = TYPE_ACTIVATION;
    456   MobileActivator::GetInstance()->AddObserver(this);
    457   MobileActivator::GetInstance()->InitiateActivation(path.substr(1));
    458 }
    459 
    460 void MobileSetupHandler::HandleSetTransactionStatus(const ListValue* args) {
    461   DCHECK_EQ(TYPE_ACTIVATION, type_);
    462   if (!web_ui())
    463     return;
    464 
    465   const size_t kSetTransactionStatusParamCount = 1;
    466   if (args->GetSize() != kSetTransactionStatusParamCount)
    467     return;
    468   // Get change callback function name.
    469   std::string status;
    470   if (!args->GetString(0, &status))
    471     return;
    472 
    473   MobileActivator::GetInstance()->OnSetTransactionStatus(
    474       LowerCaseEqualsASCII(status, kJsApiResultOK));
    475 }
    476 
    477 void MobileSetupHandler::HandlePaymentPortalLoad(const ListValue* args) {
    478   // Only activation flow webui is interested in these events.
    479   if (type_ != TYPE_ACTIVATION || !web_ui())
    480     return;
    481 
    482   const size_t kPaymentPortalLoadParamCount = 1;
    483   if (args->GetSize() != kPaymentPortalLoadParamCount)
    484     return;
    485   // Get change callback function name.
    486   std::string result;
    487   if (!args->GetString(0, &result))
    488     return;
    489 
    490   MobileActivator::GetInstance()->OnPortalLoaded(
    491       LowerCaseEqualsASCII(result, kJsApiResultOK));
    492 }
    493 
    494 void MobileSetupHandler::HandleGetDeviceInfo(const ListValue* args) {
    495   DCHECK_NE(TYPE_ACTIVATION, type_);
    496   if (!web_ui())
    497     return;
    498 
    499   std::string path = web_ui()->GetWebContents()->GetURL().path();
    500   if (path.empty())
    501     return;
    502 
    503   chromeos::NetworkStateHandler* nsh =
    504       NetworkHandler::Get()->network_state_handler();
    505   // TODO: Figure out why the path has an extra '/' in the front. (e.g. It is
    506   // '//service/5' instead of '/service/5'.
    507   const NetworkState* network = nsh->GetNetworkState(path.substr(1));
    508   if (!network) {
    509     web_ui()->GetWebContents()->Close();
    510     return;
    511   }
    512 
    513   // If this is the initial call, update the network status and start observing
    514   // network changes, but only for LTE networks. The other networks should
    515   // ignore network status.
    516   if (type_ == TYPE_UNDETERMINED) {
    517     if (network->network_technology() == shill::kNetworkTechnologyLte ||
    518         network->network_technology() == shill::kNetworkTechnologyLteAdvanced) {
    519       type_ = TYPE_PORTAL_LTE;
    520       nsh->AddObserver(this, FROM_HERE);
    521       // Update the network status and notify the webui. This is the initial
    522       // network state so the webui should be notified no matter what.
    523       UpdatePortalReachability(network,
    524                                true /* force notification */);
    525     } else {
    526       type_ = TYPE_PORTAL;
    527       // For non-LTE networks network state is ignored, so report the portal is
    528       // reachable, so it gets shown.
    529       web_ui()->CallJavascriptFunction(kJsConnectivityChangedCallback,
    530                                        base::FundamentalValue(true));
    531     }
    532   }
    533 
    534   NetworkHandler::Get()->network_configuration_handler()->GetProperties(
    535       network->path(),
    536       base::Bind(&MobileSetupHandler::GetPropertiesAndCallGetDeviceInfo,
    537                  weak_ptr_factory_.GetWeakPtr()),
    538       base::Bind(&MobileSetupHandler::GetPropertiesFailure,
    539                  weak_ptr_factory_.GetWeakPtr(),
    540                  network->path(),
    541                  kJsGetDeviceInfoCallback));
    542 }
    543 
    544 void MobileSetupHandler::GetPropertiesAndCallGetDeviceInfo(
    545     const std::string& service_path,
    546     const base::DictionaryValue& properties) {
    547   DictionaryValue device_info;
    548   GetDeviceInfo(properties, &device_info);
    549   web_ui()->CallJavascriptFunction(kJsGetDeviceInfoCallback, device_info);
    550 }
    551 
    552 void MobileSetupHandler::GetPropertiesFailure(
    553     const std::string& service_path,
    554     const std::string& callback_name,
    555     const std::string& error_name,
    556     scoped_ptr<base::DictionaryValue> error_data) {
    557   NET_LOG_ERROR("MobileActivator GetProperties Failed: " + error_name,
    558                 service_path);
    559   // Invoke |callback_name| with an empty dictionary.
    560   DictionaryValue device_dict;
    561   web_ui()->CallJavascriptFunction(callback_name, device_dict);
    562 }
    563 
    564 void MobileSetupHandler::DefaultNetworkChanged(
    565     const NetworkState* default_network) {
    566   if (!web_ui())
    567     return;
    568 
    569   std::string path = web_ui()->GetWebContents()->GetURL().path().substr(1);
    570   if (path.empty())
    571     return;
    572 
    573   const NetworkState* network =
    574       NetworkHandler::Get()->network_state_handler()->GetNetworkState(path);
    575   if (!network) {
    576     LOG(ERROR) << "Service path lost";
    577     web_ui()->GetWebContents()->Close();
    578     return;
    579   }
    580 
    581   UpdatePortalReachability(network, false /* do not force notification */);
    582 }
    583 
    584 void MobileSetupHandler::NetworkConnectionStateChanged(
    585     const NetworkState* network) {
    586   if (!web_ui())
    587     return;
    588 
    589   std::string path = web_ui()->GetWebContents()->GetURL().path().substr(1);
    590   if (path.empty() || path != network->path())
    591     return;
    592 
    593   UpdatePortalReachability(network, false /* do not force notification */);
    594 }
    595 
    596 void MobileSetupHandler::UpdatePortalReachability(
    597     const NetworkState* network,
    598     bool force_notification) {
    599   DCHECK(web_ui());
    600 
    601   DCHECK_EQ(type_, TYPE_PORTAL_LTE);
    602 
    603   chromeos::NetworkStateHandler* nsh =
    604       NetworkHandler::Get()->network_state_handler();
    605   bool portal_reachable =
    606       (network->IsConnectedState() ||
    607        (nsh->DefaultNetwork() &&
    608         nsh->DefaultNetwork()->connection_state() == shill::kStateOnline));
    609 
    610   if (force_notification || portal_reachable != lte_portal_reachable_) {
    611     web_ui()->CallJavascriptFunction(kJsConnectivityChangedCallback,
    612                                      base::FundamentalValue(portal_reachable));
    613   }
    614 
    615   lte_portal_reachable_ = portal_reachable;
    616 }
    617 
    618 ////////////////////////////////////////////////////////////////////////////////
    619 //
    620 // MobileSetupUI
    621 //
    622 ////////////////////////////////////////////////////////////////////////////////
    623 
    624 MobileSetupUI::MobileSetupUI(content::WebUI* web_ui)
    625     : WebUIController(web_ui) {
    626   web_ui->AddMessageHandler(new MobileSetupHandler());
    627   MobileSetupUIHTMLSource* html_source = new MobileSetupUIHTMLSource();
    628 
    629   // Set up the chrome://mobilesetup/ source.
    630   Profile* profile = Profile::FromWebUI(web_ui);
    631   content::URLDataSource::Add(profile, html_source);
    632 
    633   content::WebContentsObserver::Observe(web_ui->GetWebContents());
    634 }
    635 
    636 void MobileSetupUI::DidCommitProvisionalLoadForFrame(
    637     int64 frame_id,
    638     const base::string16& frame_unique_name,
    639     bool is_main_frame,
    640     const GURL& url,
    641     content::PageTransition transition_type,
    642     content::RenderViewHost* render_view_host) {
    643   if (frame_unique_name != UTF8ToUTF16("paymentForm"))
    644     return;
    645 
    646   web_ui()->CallJavascriptFunction(
    647         kJsPortalFrameLoadCompletedCallback);
    648 }
    649 
    650 void MobileSetupUI::DidFailProvisionalLoad(
    651     int64 frame_id,
    652     const base::string16& frame_unique_name,
    653     bool is_main_frame,
    654     const GURL& validated_url,
    655     int error_code,
    656     const base::string16& error_description,
    657     content::RenderViewHost* render_view_host) {
    658   if (frame_unique_name != UTF8ToUTF16("paymentForm"))
    659     return;
    660 
    661   base::FundamentalValue result_value(-error_code);
    662   web_ui()->CallJavascriptFunction(kJsPortalFrameLoadFailedCallback,
    663                                    result_value);
    664 }
    665