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