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/choose_mobile_network_ui.h"
      6 
      7 #include <set>
      8 #include <string>
      9 
     10 #include "base/bind.h"
     11 #include "base/bind_helpers.h"
     12 #include "base/location.h"
     13 #include "base/logging.h"
     14 #include "base/strings/string_number_conversions.h"
     15 #include "base/strings/string_piece.h"
     16 #include "base/values.h"
     17 #include "chrome/browser/profiles/profile.h"
     18 #include "chrome/common/url_constants.h"
     19 #include "chromeos/network/device_state.h"
     20 #include "chromeos/network/network_device_handler.h"
     21 #include "chromeos/network/network_event_log.h"
     22 #include "chromeos/network/network_state_handler.h"
     23 #include "chromeos/network/network_state_handler_observer.h"
     24 #include "content/public/browser/web_contents.h"
     25 #include "content/public/browser/web_ui.h"
     26 #include "content/public/browser/web_ui_data_source.h"
     27 #include "content/public/browser/web_ui_message_handler.h"
     28 #include "grit/browser_resources.h"
     29 #include "grit/generated_resources.h"
     30 #include "third_party/cros_system_api/dbus/service_constants.h"
     31 #include "ui/base/l10n/l10n_util.h"
     32 #include "ui/base/resource/resource_bundle.h"
     33 
     34 using content::WebContents;
     35 using content::WebUIMessageHandler;
     36 
     37 namespace chromeos {
     38 
     39 namespace {
     40 
     41 // JS API callbacks names.
     42 const char kJsApiCancel[] = "cancel";
     43 const char kJsApiConnect[] = "connect";
     44 const char kJsApiPageReady[] = "pageReady";
     45 
     46 // Page JS API function names.
     47 const char kJsApiShowNetworks[] = "mobile.ChooseNetwork.showNetworks";
     48 const char kJsApiShowScanning[] = "mobile.ChooseNetwork.showScanning";
     49 
     50 // Network properties.
     51 const char kNetworkIdProperty[] = "networkId";
     52 const char kOperatorNameProperty[] = "operatorName";
     53 const char kStatusProperty[] = "status";
     54 const char kTechnologyProperty[] = "technology";
     55 
     56 content::WebUIDataSource* CreateChooseMobileNetworkUIHTMLSource() {
     57   content::WebUIDataSource* source = content::WebUIDataSource::Create(
     58       chrome::kChromeUIChooseMobileNetworkHost);
     59 
     60   source->AddLocalizedString("chooseNetworkTitle",
     61                              IDS_NETWORK_CHOOSE_MOBILE_NETWORK);
     62   source->AddLocalizedString("scanningMsgLine1",
     63                              IDS_NETWORK_SCANNING_FOR_MOBILE_NETWORKS);
     64   source->AddLocalizedString("scanningMsgLine2",
     65                              IDS_NETWORK_SCANNING_THIS_MAY_TAKE_A_MINUTE);
     66   source->AddLocalizedString("noMobileNetworks",
     67                              IDS_NETWORK_NO_MOBILE_NETWORKS);
     68   source->AddLocalizedString("connect", IDS_OPTIONS_SETTINGS_CONNECT);
     69   source->AddLocalizedString("cancel", IDS_CANCEL);
     70 
     71   source->SetUseJsonJSFormatV2();
     72   source->SetJsonPath("strings.js");
     73   source->AddResourcePath("choose_mobile_network.js",
     74                           IDR_CHOOSE_MOBILE_NETWORK_JS);
     75   source->SetDefaultResource(IDR_CHOOSE_MOBILE_NETWORK_HTML);
     76   return source;
     77 }
     78 
     79 chromeos::NetworkDeviceHandler* GetNetworkDeviceHandler() {
     80   return chromeos::NetworkHandler::Get()->network_device_handler();
     81 }
     82 
     83 chromeos::NetworkStateHandler* GetNetworkStateHandler() {
     84   return chromeos::NetworkHandler::Get()->network_state_handler();
     85 }
     86 
     87 void NetworkOperationErrorCallback(
     88     const std::string& operation_name,
     89     const std::string& error_name,
     90     scoped_ptr<base::DictionaryValue> error_data) {
     91   NET_LOG_ERROR("Operation failed: " + error_name, operation_name);
     92 }
     93 
     94 class ChooseMobileNetworkHandler
     95     : public WebUIMessageHandler,
     96       public NetworkStateHandlerObserver {
     97  public:
     98   ChooseMobileNetworkHandler();
     99   virtual ~ChooseMobileNetworkHandler();
    100 
    101   // WebUIMessageHandler implementation.
    102   virtual void RegisterMessages() OVERRIDE;
    103 
    104   // NetworkStateHandlerObserver implementation.
    105   virtual void DeviceListChanged() OVERRIDE;
    106 
    107  private:
    108   // Handlers for JS WebUI messages.
    109   void HandleCancel(const base::ListValue* args);
    110   void HandleConnect(const base::ListValue* args);
    111   void HandlePageReady(const base::ListValue* args);
    112 
    113   std::string device_path_;
    114   base::ListValue networks_list_;
    115   bool is_page_ready_;
    116   bool has_pending_results_;
    117 
    118   DISALLOW_COPY_AND_ASSIGN(ChooseMobileNetworkHandler);
    119 };
    120 
    121 // ChooseMobileNetworkHandler implementation.
    122 
    123 ChooseMobileNetworkHandler::ChooseMobileNetworkHandler()
    124     : is_page_ready_(false),
    125       has_pending_results_(false) {
    126   NetworkStateHandler* handler = GetNetworkStateHandler();
    127   const DeviceState* cellular =
    128       handler->GetDeviceStateByType(NetworkTypePattern::Cellular());
    129   if (!cellular) {
    130     NET_LOG_ERROR(
    131         "A cellular device is not available.",
    132         "Cannot initiate a cellular network scan without a cellular device.");
    133     return;
    134   }
    135   handler->AddObserver(this, FROM_HERE);
    136   device_path_ = cellular->path();
    137   GetNetworkDeviceHandler()->ProposeScan(
    138       device_path_,
    139       base::Bind(&base::DoNothing),
    140       base::Bind(&NetworkOperationErrorCallback, "ProposeScan"));
    141 }
    142 
    143 ChooseMobileNetworkHandler::~ChooseMobileNetworkHandler() {
    144   GetNetworkStateHandler()->RemoveObserver(this, FROM_HERE);
    145 }
    146 
    147 void ChooseMobileNetworkHandler::RegisterMessages() {
    148   web_ui()->RegisterMessageCallback(
    149       kJsApiCancel,
    150       base::Bind(&ChooseMobileNetworkHandler::HandleCancel,
    151                  base::Unretained(this)));
    152   web_ui()->RegisterMessageCallback(
    153       kJsApiConnect,
    154       base::Bind(&ChooseMobileNetworkHandler::HandleConnect,
    155                  base::Unretained(this)));
    156   web_ui()->RegisterMessageCallback(
    157       kJsApiPageReady,
    158       base::Bind(&ChooseMobileNetworkHandler::HandlePageReady,
    159                  base::Unretained(this)));
    160 }
    161 
    162 void ChooseMobileNetworkHandler::DeviceListChanged() {
    163   const DeviceState* cellular = GetNetworkStateHandler()->GetDeviceState(
    164       device_path_);
    165   networks_list_.Clear();
    166   if (!cellular) {
    167     LOG(WARNING) << "Cellular device with path '" << device_path_
    168                  << "' disappeared.";
    169     return;
    170   }
    171   if (cellular->scanning()) {
    172     NET_LOG_EVENT("ChooseMobileNetwork", "Device is scanning for networks.");
    173     web_ui()->CallJavascriptFunction(kJsApiShowScanning);
    174     return;
    175   }
    176   const DeviceState::CellularScanResults& scan_results =
    177       cellular->scan_results();
    178   std::set<std::string> network_ids;
    179   for (DeviceState::CellularScanResults::const_iterator it =
    180       scan_results.begin(); it != scan_results.end(); ++it) {
    181     // We need to remove duplicates from the list because same network with
    182     // different technologies are listed multiple times. But ModemManager
    183     // Register API doesn't allow technology to be specified so just show unique
    184     // network in UI.
    185     if (network_ids.insert(it->network_id).second) {
    186       base::DictionaryValue* network = new base::DictionaryValue();
    187       network->SetString(kNetworkIdProperty, it->network_id);
    188       if (!it->long_name.empty())
    189         network->SetString(kOperatorNameProperty, it->long_name);
    190       else if (!it->short_name.empty())
    191         network->SetString(kOperatorNameProperty, it->short_name);
    192       else
    193         network->SetString(kOperatorNameProperty, it->network_id);
    194       network->SetString(kStatusProperty, it->status);
    195       network->SetString(kTechnologyProperty, it->technology);
    196       networks_list_.Append(network);
    197     }
    198   }
    199   if (is_page_ready_) {
    200     web_ui()->CallJavascriptFunction(kJsApiShowNetworks, networks_list_);
    201     networks_list_.Clear();
    202     has_pending_results_ = false;
    203   } else {
    204     has_pending_results_ = true;
    205   }
    206 }
    207 
    208 void ChooseMobileNetworkHandler::HandleCancel(const base::ListValue* args) {
    209   const size_t kConnectParamCount = 0;
    210   if (args->GetSize() != kConnectParamCount) {
    211     NOTREACHED();
    212     return;
    213   }
    214 
    215   // Switch to automatic mode.
    216   GetNetworkDeviceHandler()->RegisterCellularNetwork(
    217       device_path_,
    218       "",  // An empty string is for registration with the home network.
    219       base::Bind(&base::DoNothing),
    220       base::Bind(&NetworkOperationErrorCallback,
    221                  "Register in automatic mode."));
    222 }
    223 
    224 void ChooseMobileNetworkHandler::HandleConnect(const base::ListValue* args) {
    225   std::string network_id;
    226   const size_t kConnectParamCount = 1;
    227   if (args->GetSize() != kConnectParamCount ||
    228       !args->GetString(0, &network_id)) {
    229     NOTREACHED();
    230     return;
    231   }
    232 
    233   GetNetworkDeviceHandler()->RegisterCellularNetwork(
    234       device_path_,
    235       network_id,
    236       base::Bind(&base::DoNothing),
    237       base::Bind(&NetworkOperationErrorCallback,
    238                  std::string("Register to network: ") + network_id));
    239 }
    240 
    241 void ChooseMobileNetworkHandler::HandlePageReady(const base::ListValue* args) {
    242   const size_t kConnectParamCount = 0;
    243   if (args->GetSize() != kConnectParamCount) {
    244     NOTREACHED();
    245     return;
    246   }
    247 
    248   if (has_pending_results_) {
    249     web_ui()->CallJavascriptFunction(kJsApiShowNetworks, networks_list_);
    250     networks_list_.Clear();
    251     has_pending_results_ = false;
    252   }
    253   is_page_ready_ = true;
    254 }
    255 
    256 }  // namespace
    257 
    258 ChooseMobileNetworkUI::ChooseMobileNetworkUI(content::WebUI* web_ui)
    259     : WebUIController(web_ui) {
    260   ChooseMobileNetworkHandler* handler = new ChooseMobileNetworkHandler();
    261   web_ui->AddMessageHandler(handler);
    262   // Set up the "chrome://choose-mobile-network" source.
    263   Profile* profile = Profile::FromWebUI(web_ui);
    264   content::WebUIDataSource::Add(
    265       profile, CreateChooseMobileNetworkUIHTMLSource());
    266 }
    267 
    268 }  // namespace chromeos
    269