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 "chrome/grit/generated_resources.h"
     30 #include "chrome/grit/locale_settings.h"
     31 #include "chromeos/network/device_state.h"
     32 #include "chromeos/network/network_configuration_handler.h"
     33 #include "chromeos/network/network_event_log.h"
     34 #include "chromeos/network/network_state.h"
     35 #include "chromeos/network/network_state_handler.h"
     36 #include "chromeos/network/network_state_handler_observer.h"
     37 #include "content/public/browser/browser_thread.h"
     38 #include "content/public/browser/render_frame_host.h"
     39 #include "content/public/browser/url_data_source.h"
     40 #include "content/public/browser/web_contents.h"
     41 #include "content/public/browser/web_ui.h"
     42 #include "content/public/browser/web_ui_message_handler.h"
     43 #include "grit/browser_resources.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 base::DictionaryValue& properties,
     89                    base::DictionaryValue* value) {
     90   std::string name;
     91   properties.GetStringWithoutPathExpansion(shill::kNameProperty, &name);
     92   std::string activation_type;
     93   properties.GetStringWithoutPathExpansion(
     94       shill::kActivationTypeProperty,
     95       &activation_type);
     96   const base::DictionaryValue* payment_dict;
     97   std::string payment_url, post_method, post_data;
     98   if (properties.GetDictionaryWithoutPathExpansion(
     99           shill::kPaymentPortalProperty, &payment_dict)) {
    100     payment_dict->GetStringWithoutPathExpansion(
    101         shill::kPaymentPortalURL, &payment_url);
    102     payment_dict->GetStringWithoutPathExpansion(
    103         shill::kPaymentPortalMethod, &post_method);
    104     payment_dict->GetStringWithoutPathExpansion(
    105         shill::kPaymentPortalPostData, &post_data);
    106   }
    107 
    108   value->SetString("activation_type", activation_type);
    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                                 base::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_frame_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 base::ListValue* args);
    227   void HandleStartActivation(const base::ListValue* args);
    228   void HandlePaymentPortalLoad(const base::ListValue* args);
    229   void HandleGetDeviceInfo(const base::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_frame_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 base::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   base::DictionaryValue strings;
    314 
    315   strings.SetString("connecting_header",
    316                     l10n_util::GetStringFUTF16(IDS_MOBILE_CONNECTING_HEADER,
    317                                                base::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   webui::UseVersion2 version_2;
    342 
    343   // The webui differs based on whether the network is activated or not. If the
    344   // network is activated, the webui goes straight to portal. Otherwise the
    345   // webui is used for activation flow.
    346   std::string full_html;
    347   if (activation_state == shill::kActivationStateActivated) {
    348     static const base::StringPiece html_for_activated(
    349         ResourceBundle::GetSharedInstance().GetRawDataResource(
    350             IDR_MOBILE_SETUP_PORTAL_PAGE_HTML));
    351     full_html = webui::GetI18nTemplateHtml(html_for_activated, &strings);
    352   } else {
    353     static const base::StringPiece html_for_non_activated(
    354         ResourceBundle::GetSharedInstance().GetRawDataResource(
    355             IDR_MOBILE_SETUP_PAGE_HTML));
    356     full_html = webui::GetI18nTemplateHtml(html_for_non_activated, &strings);
    357   }
    358 
    359   callback.Run(base::RefCountedString::TakeString(&full_html));
    360 }
    361 
    362 void MobileSetupUIHTMLSource::GetPropertiesFailure(
    363     const content::URLDataSource::GotDataCallback& callback,
    364     const std::string& service_path,
    365     const std::string& error_name,
    366     scoped_ptr<base::DictionaryValue> error_data) {
    367   DataRequestFailed(service_path, callback);
    368 }
    369 
    370 ////////////////////////////////////////////////////////////////////////////////
    371 //
    372 // MobileSetupHandler
    373 //
    374 ////////////////////////////////////////////////////////////////////////////////
    375 MobileSetupHandler::MobileSetupHandler()
    376     : type_(TYPE_UNDETERMINED),
    377       lte_portal_reachable_(true),
    378       weak_ptr_factory_(this) {
    379 }
    380 
    381 MobileSetupHandler::~MobileSetupHandler() {
    382   if (type_ == TYPE_ACTIVATION) {
    383     MobileActivator::GetInstance()->RemoveObserver(this);
    384     MobileActivator::GetInstance()->TerminateActivation();
    385   } else if (type_ == TYPE_PORTAL_LTE) {
    386     NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
    387                                                                    FROM_HERE);
    388   }
    389 }
    390 
    391 void MobileSetupHandler::OnActivationStateChanged(
    392     const NetworkState* network,
    393     MobileActivator::PlanActivationState state,
    394     const std::string& error_description) {
    395   DCHECK_EQ(TYPE_ACTIVATION, type_);
    396   if (!web_ui())
    397     return;
    398 
    399   if (!network) {
    400     base::DictionaryValue device_dict;
    401     SetActivationStateAndError(state, error_description, &device_dict);
    402     web_ui()->CallJavascriptFunction(kJsDeviceStatusChangedCallback,
    403                                      device_dict);
    404     return;
    405   }
    406 
    407   NetworkHandler::Get()->network_configuration_handler()->GetProperties(
    408       network->path(),
    409       base::Bind(&MobileSetupHandler::GetPropertiesAndCallStatusChanged,
    410                  weak_ptr_factory_.GetWeakPtr(),
    411                  state,
    412                  error_description),
    413       base::Bind(&MobileSetupHandler::GetPropertiesFailure,
    414                  weak_ptr_factory_.GetWeakPtr(),
    415                  network->path(),
    416                  kJsDeviceStatusChangedCallback));
    417 }
    418 
    419 void MobileSetupHandler::GetPropertiesAndCallStatusChanged(
    420     MobileActivator::PlanActivationState state,
    421     const std::string& error_description,
    422     const std::string& service_path,
    423     const base::DictionaryValue& properties) {
    424   base::DictionaryValue device_dict;
    425   GetDeviceInfo(properties, &device_dict);
    426   SetActivationStateAndError(state, error_description, &device_dict);
    427   web_ui()->CallJavascriptFunction(kJsDeviceStatusChangedCallback, device_dict);
    428 }
    429 
    430 void MobileSetupHandler::RegisterMessages() {
    431   web_ui()->RegisterMessageCallback(kJsApiStartActivation,
    432       base::Bind(&MobileSetupHandler::HandleStartActivation,
    433                  base::Unretained(this)));
    434   web_ui()->RegisterMessageCallback(kJsApiSetTransactionStatus,
    435       base::Bind(&MobileSetupHandler::HandleSetTransactionStatus,
    436                  base::Unretained(this)));
    437   web_ui()->RegisterMessageCallback(kJsApiPaymentPortalLoad,
    438       base::Bind(&MobileSetupHandler::HandlePaymentPortalLoad,
    439                  base::Unretained(this)));
    440   web_ui()->RegisterMessageCallback(kJsGetDeviceInfo,
    441       base::Bind(&MobileSetupHandler::HandleGetDeviceInfo,
    442                  base::Unretained(this)));
    443 }
    444 
    445 void MobileSetupHandler::HandleStartActivation(const base::ListValue* args) {
    446   DCHECK_EQ(TYPE_UNDETERMINED, type_);
    447 
    448   if (!web_ui())
    449     return;
    450 
    451   std::string path = web_ui()->GetWebContents()->GetURL().path();
    452   if (!path.size())
    453     return;
    454 
    455   LOG(WARNING) << "Starting activation for service " << path;
    456 
    457   type_ = TYPE_ACTIVATION;
    458   MobileActivator::GetInstance()->AddObserver(this);
    459   MobileActivator::GetInstance()->InitiateActivation(path.substr(1));
    460 }
    461 
    462 void MobileSetupHandler::HandleSetTransactionStatus(
    463     const base::ListValue* args) {
    464   DCHECK_EQ(TYPE_ACTIVATION, type_);
    465   if (!web_ui())
    466     return;
    467 
    468   const size_t kSetTransactionStatusParamCount = 1;
    469   if (args->GetSize() != kSetTransactionStatusParamCount)
    470     return;
    471   // Get change callback function name.
    472   std::string status;
    473   if (!args->GetString(0, &status))
    474     return;
    475 
    476   MobileActivator::GetInstance()->OnSetTransactionStatus(
    477       LowerCaseEqualsASCII(status, kJsApiResultOK));
    478 }
    479 
    480 void MobileSetupHandler::HandlePaymentPortalLoad(const base::ListValue* args) {
    481   // Only activation flow webui is interested in these events.
    482   if (type_ != TYPE_ACTIVATION || !web_ui())
    483     return;
    484 
    485   const size_t kPaymentPortalLoadParamCount = 1;
    486   if (args->GetSize() != kPaymentPortalLoadParamCount)
    487     return;
    488   // Get change callback function name.
    489   std::string result;
    490   if (!args->GetString(0, &result))
    491     return;
    492 
    493   MobileActivator::GetInstance()->OnPortalLoaded(
    494       LowerCaseEqualsASCII(result, kJsApiResultOK));
    495 }
    496 
    497 void MobileSetupHandler::HandleGetDeviceInfo(const base::ListValue* args) {
    498   DCHECK_NE(TYPE_ACTIVATION, type_);
    499   if (!web_ui())
    500     return;
    501 
    502   std::string path = web_ui()->GetWebContents()->GetURL().path();
    503   if (path.empty())
    504     return;
    505 
    506   chromeos::NetworkStateHandler* nsh =
    507       NetworkHandler::Get()->network_state_handler();
    508   // TODO: Figure out why the path has an extra '/' in the front. (e.g. It is
    509   // '//service/5' instead of '/service/5'.
    510   const NetworkState* network = nsh->GetNetworkState(path.substr(1));
    511   if (!network) {
    512     web_ui()->GetWebContents()->Close();
    513     return;
    514   }
    515 
    516   // If this is the initial call, update the network status and start observing
    517   // network changes, but only for LTE networks. The other networks should
    518   // ignore network status.
    519   if (type_ == TYPE_UNDETERMINED) {
    520     if (network->network_technology() == shill::kNetworkTechnologyLte ||
    521         network->network_technology() == shill::kNetworkTechnologyLteAdvanced) {
    522       type_ = TYPE_PORTAL_LTE;
    523       nsh->AddObserver(this, FROM_HERE);
    524       // Update the network status and notify the webui. This is the initial
    525       // network state so the webui should be notified no matter what.
    526       UpdatePortalReachability(network,
    527                                true /* force notification */);
    528     } else {
    529       type_ = TYPE_PORTAL;
    530       // For non-LTE networks network state is ignored, so report the portal is
    531       // reachable, so it gets shown.
    532       web_ui()->CallJavascriptFunction(kJsConnectivityChangedCallback,
    533                                        base::FundamentalValue(true));
    534     }
    535   }
    536 
    537   NetworkHandler::Get()->network_configuration_handler()->GetProperties(
    538       network->path(),
    539       base::Bind(&MobileSetupHandler::GetPropertiesAndCallGetDeviceInfo,
    540                  weak_ptr_factory_.GetWeakPtr()),
    541       base::Bind(&MobileSetupHandler::GetPropertiesFailure,
    542                  weak_ptr_factory_.GetWeakPtr(),
    543                  network->path(),
    544                  kJsGetDeviceInfoCallback));
    545 }
    546 
    547 void MobileSetupHandler::GetPropertiesAndCallGetDeviceInfo(
    548     const std::string& service_path,
    549     const base::DictionaryValue& properties) {
    550   base::DictionaryValue device_info;
    551   GetDeviceInfo(properties, &device_info);
    552   web_ui()->CallJavascriptFunction(kJsGetDeviceInfoCallback, device_info);
    553 }
    554 
    555 void MobileSetupHandler::GetPropertiesFailure(
    556     const std::string& service_path,
    557     const std::string& callback_name,
    558     const std::string& error_name,
    559     scoped_ptr<base::DictionaryValue> error_data) {
    560   NET_LOG_ERROR("MobileActivator GetProperties Failed: " + error_name,
    561                 service_path);
    562   // Invoke |callback_name| with an empty dictionary.
    563   base::DictionaryValue device_dict;
    564   web_ui()->CallJavascriptFunction(callback_name, device_dict);
    565 }
    566 
    567 void MobileSetupHandler::DefaultNetworkChanged(
    568     const NetworkState* default_network) {
    569   if (!web_ui())
    570     return;
    571 
    572   std::string path = web_ui()->GetWebContents()->GetURL().path().substr(1);
    573   if (path.empty())
    574     return;
    575 
    576   const NetworkState* network =
    577       NetworkHandler::Get()->network_state_handler()->GetNetworkState(path);
    578   if (!network) {
    579     LOG(ERROR) << "Service path lost";
    580     web_ui()->GetWebContents()->Close();
    581     return;
    582   }
    583 
    584   UpdatePortalReachability(network, false /* do not force notification */);
    585 }
    586 
    587 void MobileSetupHandler::NetworkConnectionStateChanged(
    588     const NetworkState* network) {
    589   if (!web_ui())
    590     return;
    591 
    592   std::string path = web_ui()->GetWebContents()->GetURL().path().substr(1);
    593   if (path.empty() || path != network->path())
    594     return;
    595 
    596   UpdatePortalReachability(network, false /* do not force notification */);
    597 }
    598 
    599 void MobileSetupHandler::UpdatePortalReachability(
    600     const NetworkState* network,
    601     bool force_notification) {
    602   DCHECK(web_ui());
    603 
    604   DCHECK_EQ(type_, TYPE_PORTAL_LTE);
    605 
    606   chromeos::NetworkStateHandler* nsh =
    607       NetworkHandler::Get()->network_state_handler();
    608   bool portal_reachable =
    609       (network->IsConnectedState() ||
    610        (nsh->DefaultNetwork() &&
    611         nsh->DefaultNetwork()->connection_state() == shill::kStateOnline));
    612 
    613   if (force_notification || portal_reachable != lte_portal_reachable_) {
    614     web_ui()->CallJavascriptFunction(kJsConnectivityChangedCallback,
    615                                      base::FundamentalValue(portal_reachable));
    616   }
    617 
    618   lte_portal_reachable_ = portal_reachable;
    619 }
    620 
    621 ////////////////////////////////////////////////////////////////////////////////
    622 //
    623 // MobileSetupUI
    624 //
    625 ////////////////////////////////////////////////////////////////////////////////
    626 
    627 MobileSetupUI::MobileSetupUI(content::WebUI* web_ui)
    628     : WebUIController(web_ui) {
    629   web_ui->AddMessageHandler(new MobileSetupHandler());
    630   MobileSetupUIHTMLSource* html_source = new MobileSetupUIHTMLSource();
    631 
    632   // Set up the chrome://mobilesetup/ source.
    633   Profile* profile = Profile::FromWebUI(web_ui);
    634   content::URLDataSource::Add(profile, html_source);
    635 
    636   content::WebContentsObserver::Observe(web_ui->GetWebContents());
    637 }
    638 
    639 void MobileSetupUI::DidCommitProvisionalLoadForFrame(
    640     content::RenderFrameHost* render_frame_host,
    641     const GURL& url,
    642     ui::PageTransition transition_type) {
    643   if (render_frame_host->GetFrameName() != "paymentForm")
    644     return;
    645 
    646   web_ui()->CallJavascriptFunction(
    647         kJsPortalFrameLoadCompletedCallback);
    648 }
    649 
    650 void MobileSetupUI::DidFailProvisionalLoad(
    651     content::RenderFrameHost* render_frame_host,
    652     const GURL& validated_url,
    653     int error_code,
    654     const base::string16& error_description) {
    655   if (render_frame_host->GetFrameName() != "paymentForm")
    656     return;
    657 
    658   base::FundamentalValue result_value(-error_code);
    659   web_ui()->CallJavascriptFunction(kJsPortalFrameLoadFailedCallback,
    660                                    result_value);
    661 }
    662