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 
     49 // Network properties.
     50 const char kNetworkIdProperty[] = "networkId";
     51 const char kOperatorNameProperty[] = "operatorName";
     52 const char kStatusProperty[] = "status";
     53 const char kTechnologyProperty[] = "technology";
     54 
     55 content::WebUIDataSource* CreateChooseMobileNetworkUIHTMLSource() {
     56   content::WebUIDataSource* source = content::WebUIDataSource::Create(
     57       chrome::kChromeUIChooseMobileNetworkHost);
     58 
     59   source->AddLocalizedString("chooseNetworkTitle",
     60                              IDS_NETWORK_CHOOSE_MOBILE_NETWORK);
     61   source->AddLocalizedString("scanningMsgLine1",
     62                              IDS_NETWORK_SCANNING_FOR_MOBILE_NETWORKS);
     63   source->AddLocalizedString("scanningMsgLine2",
     64                              IDS_NETWORK_SCANNING_THIS_MAY_TAKE_A_MINUTE);
     65   source->AddLocalizedString("noMobileNetworks",
     66                              IDS_NETWORK_NO_MOBILE_NETWORKS);
     67   source->AddLocalizedString("connect", IDS_OPTIONS_SETTINGS_CONNECT);
     68   source->AddLocalizedString("cancel", IDS_CANCEL);
     69 
     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 ListValue* args);
    108   void HandleConnect(const ListValue* args);
    109   void HandlePageReady(const ListValue* args);
    110 
    111   std::string device_path_;
    112   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 = handler->GetDeviceStateByType(
    126       flimflam::kTypeCellular);
    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   const DeviceState::CellularScanResults& scan_results =
    170       cellular->scan_results();
    171   std::set<std::string> network_ids;
    172   for (DeviceState::CellularScanResults::const_iterator it =
    173       scan_results.begin(); it != scan_results.end(); ++it) {
    174     // We need to remove duplicates from the list because same network with
    175     // different technologies are listed multiple times. But ModemManager
    176     // Register API doesn't allow technology to be specified so just show unique
    177     // network in UI.
    178     if (network_ids.insert(it->network_id).second) {
    179       DictionaryValue* network = new DictionaryValue();
    180       network->SetString(kNetworkIdProperty, it->network_id);
    181       if (!it->long_name.empty())
    182         network->SetString(kOperatorNameProperty, it->long_name);
    183       else if (!it->short_name.empty())
    184         network->SetString(kOperatorNameProperty, it->short_name);
    185       else
    186         network->SetString(kOperatorNameProperty, it->network_id);
    187       network->SetString(kStatusProperty, it->status);
    188       network->SetString(kTechnologyProperty, it->technology);
    189       networks_list_.Append(network);
    190     }
    191   }
    192   if (is_page_ready_) {
    193     web_ui()->CallJavascriptFunction(kJsApiShowNetworks, networks_list_);
    194     networks_list_.Clear();
    195     has_pending_results_ = false;
    196   } else {
    197     has_pending_results_ = true;
    198   }
    199 }
    200 
    201 void ChooseMobileNetworkHandler::HandleCancel(const ListValue* args) {
    202   const size_t kConnectParamCount = 0;
    203   if (args->GetSize() != kConnectParamCount) {
    204     NOTREACHED();
    205     return;
    206   }
    207 
    208   // Switch to automatic mode.
    209   GetNetworkDeviceHandler()->RegisterCellularNetwork(
    210       device_path_,
    211       "",  // An empty string is for registration with the home network.
    212       base::Bind(&base::DoNothing),
    213       base::Bind(&NetworkOperationErrorCallback,
    214                  "Register in automatic mode."));
    215 }
    216 
    217 void ChooseMobileNetworkHandler::HandleConnect(const ListValue* args) {
    218   std::string network_id;
    219   const size_t kConnectParamCount = 1;
    220   if (args->GetSize() != kConnectParamCount ||
    221       !args->GetString(0, &network_id)) {
    222     NOTREACHED();
    223     return;
    224   }
    225 
    226   GetNetworkDeviceHandler()->RegisterCellularNetwork(
    227       device_path_,
    228       network_id,
    229       base::Bind(&base::DoNothing),
    230       base::Bind(&NetworkOperationErrorCallback,
    231                  std::string("Register to network: ") + network_id));
    232 }
    233 
    234 void ChooseMobileNetworkHandler::HandlePageReady(const ListValue* args) {
    235   const size_t kConnectParamCount = 0;
    236   if (args->GetSize() != kConnectParamCount) {
    237     NOTREACHED();
    238     return;
    239   }
    240 
    241   if (has_pending_results_) {
    242     web_ui()->CallJavascriptFunction(kJsApiShowNetworks, networks_list_);
    243     networks_list_.Clear();
    244     has_pending_results_ = false;
    245   }
    246   is_page_ready_ = true;
    247 }
    248 
    249 }  // namespace
    250 
    251 ChooseMobileNetworkUI::ChooseMobileNetworkUI(content::WebUI* web_ui)
    252     : WebUIController(web_ui) {
    253   ChooseMobileNetworkHandler* handler = new ChooseMobileNetworkHandler();
    254   web_ui->AddMessageHandler(handler);
    255   // Set up the "chrome://choose-mobile-network" source.
    256   Profile* profile = Profile::FromWebUI(web_ui);
    257   content::WebUIDataSource::Add(
    258       profile, CreateChooseMobileNetworkUIHTMLSource());
    259 }
    260 
    261 }  // namespace chromeos
    262