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