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