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