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