Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(538)

Side by Side Diff: chrome/browser/ui/webui/options2/chromeos/internet_options_handler2.cc

Issue 10698140: Remove "2" suffixes from options2 code. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/options2/chromeos/internet_options_handler2.h"
6
7 #include <ctype.h>
8
9 #include <map>
10 #include <string>
11 #include <vector>
12
13 #include "ash/shell.h"
14 #include "ash/shell_delegate.h"
15 #include "base/base64.h"
16 #include "base/basictypes.h"
17 #include "base/bind.h"
18 #include "base/bind_helpers.h"
19 #include "base/command_line.h"
20 #include "base/i18n/time_formatting.h"
21 #include "base/string16.h"
22 #include "base/string_number_conversions.h"
23 #include "base/stringprintf.h"
24 #include "base/time.h"
25 #include "base/utf_string_conversions.h"
26 #include "base/values.h"
27 #include "chrome/browser/browser_process.h"
28 #include "chrome/browser/chromeos/choose_mobile_network_dialog.h"
29 #include "chrome/browser/chromeos/cros/cros_library.h"
30 #include "chrome/browser/chromeos/cros/network_library.h"
31 #include "chrome/browser/chromeos/cros/onc_constants.h"
32 #include "chrome/browser/chromeos/cros_settings.h"
33 #include "chrome/browser/chromeos/enrollment_dialog_view.h"
34 #include "chrome/browser/chromeos/mobile_config.h"
35 #include "chrome/browser/chromeos/options/network_config_view.h"
36 #include "chrome/browser/chromeos/proxy_config_service_impl.h"
37 #include "chrome/browser/chromeos/sim_dialog_delegate.h"
38 #include "chrome/browser/chromeos/status/network_menu_icon.h"
39 #include "chrome/browser/net/pref_proxy_config_tracker.h"
40 #include "chrome/browser/profiles/profile.h"
41 #include "chrome/browser/profiles/profile_manager.h"
42 #include "chrome/browser/ui/browser.h"
43 #include "chrome/browser/ui/browser_finder.h"
44 #include "chrome/browser/ui/browser_window.h"
45 #include "chrome/browser/ui/singleton_tabs.h"
46 #include "chrome/browser/ui/webui/web_ui_util.h"
47 #include "chrome/common/chrome_notification_types.h"
48 #include "chrome/common/chrome_switches.h"
49 #include "chrome/common/time_format.h"
50 #include "content/public/browser/notification_service.h"
51 #include "content/public/browser/web_contents.h"
52 #include "content/public/browser/web_ui.h"
53 #include "grit/chromium_strings.h"
54 #include "grit/generated_resources.h"
55 #include "grit/locale_settings.h"
56 #include "grit/theme_resources.h"
57 #include "ui/base/layout.h"
58 #include "ui/base/l10n/l10n_util.h"
59 #include "ui/base/resource/resource_bundle.h"
60 #include "ui/gfx/display.h"
61 #include "ui/gfx/image/image_skia.h"
62 #include "ui/gfx/screen.h"
63 #include "ui/views/widget/widget.h"
64
65 namespace {
66
67 static const char kOtherNetworksFakePath[] = "?";
68
69 // Keys for the network description dictionary passed to the web ui. Make sure
70 // to keep the strings in sync with what the Javascript side uses.
71 const char kNetworkInfoKeyActivationState[] = "activation_state";
72 const char kNetworkInfoKeyConnectable[] = "connectable";
73 const char kNetworkInfoKeyConnected[] = "connected";
74 const char kNetworkInfoKeyConnecting[] = "connecting";
75 const char kNetworkInfoKeyIconURL[] = "iconURL";
76 const char kNetworkInfoKeyNeedsNewPlan[] = "needs_new_plan";
77 const char kNetworkInfoKeyNetworkName[] = "networkName";
78 const char kNetworkInfoKeyNetworkStatus[] = "networkStatus";
79 const char kNetworkInfoKeyNetworkType[] = "networkType";
80 const char kNetworkInfoKeyRemembered[] = "remembered";
81 const char kNetworkInfoKeyServicePath[] = "servicePath";
82 const char kNetworkInfoKeyPolicyManaged[] = "policyManaged";
83
84 // A helper class for building network information dictionaries to be sent to
85 // the webui code.
86 class NetworkInfoDictionary {
87 public:
88 // Initializes the dictionary with default values.
89 explicit NetworkInfoDictionary(float icon_scale);
90
91 // Copies in service path, connect{ing|ed|able} flags and connection type from
92 // the provided network object. Also chooses an appropriate icon based on the
93 // network type.
94 NetworkInfoDictionary(const chromeos::Network* network,
95 float icon_scale);
96
97 // Initializes a remembered network entry, pulling information from the passed
98 // network object and the corresponding remembered network object. |network|
99 // may be NULL.
100 NetworkInfoDictionary(const chromeos::Network* network,
101 const chromeos::Network* remembered,
102 float icon_scale);
103
104 // Setters for filling in information.
105 void set_service_path(const std::string& service_path) {
106 service_path_ = service_path;
107 }
108 void set_icon(const gfx::ImageSkia& icon) {
109 gfx::ImageSkiaRep image_rep = icon.GetRepresentation(icon_scale_factor_);
110 icon_url_ = icon.isNull() ? "" : web_ui_util::GetImageDataUrl(
111 image_rep.sk_bitmap());
112 }
113 void set_name(const std::string& name) {
114 name_ = name;
115 }
116 void set_connecting(bool connecting) {
117 connecting_ = connecting;
118 }
119 void set_connected(bool connected) {
120 connected_ = connected;
121 }
122 void set_connectable(bool connectable) {
123 connectable_ = connectable;
124 }
125 void set_connection_type(chromeos::ConnectionType connection_type) {
126 connection_type_ = connection_type;
127 }
128 void set_remembered(bool remembered) {
129 remembered_ = remembered;
130 }
131 void set_shared(bool shared) {
132 shared_ = shared;
133 }
134 void set_activation_state(chromeos::ActivationState activation_state) {
135 activation_state_ = activation_state;
136 }
137 void set_needs_new_plan(bool needs_new_plan) {
138 needs_new_plan_ = needs_new_plan;
139 }
140 void set_policy_managed(bool policy_managed) {
141 policy_managed_ = policy_managed;
142 }
143
144 // Builds the DictionaryValue representation from the previously set
145 // parameters. Ownership of the returned pointer is transferred to the caller.
146 DictionaryValue* BuildDictionary();
147
148 private:
149 // Values to be filled into the dictionary.
150 std::string service_path_;
151 std::string icon_url_;
152 std::string name_;
153 bool connecting_;
154 bool connected_;
155 bool connectable_;
156 chromeos::ConnectionType connection_type_;
157 bool remembered_;
158 bool shared_;
159 chromeos::ActivationState activation_state_;
160 bool needs_new_plan_;
161 bool policy_managed_;
162 ui::ScaleFactor icon_scale_factor_;
163
164 DISALLOW_COPY_AND_ASSIGN(NetworkInfoDictionary);
165 };
166
167 NetworkInfoDictionary::NetworkInfoDictionary(
168 float icon_scale)
169 : icon_scale_factor_(ui::GetScaleFactorFromScale(icon_scale)) {
170 set_connecting(false);
171 set_connected(false);
172 set_connectable(false);
173 set_remembered(false);
174 set_shared(false);
175 set_activation_state(chromeos::ACTIVATION_STATE_UNKNOWN);
176 set_needs_new_plan(false);
177 set_policy_managed(false);
178 }
179
180 NetworkInfoDictionary::NetworkInfoDictionary(const chromeos::Network* network,
181 float icon_scale)
182 : icon_scale_factor_(ui::GetScaleFactorFromScale(icon_scale)) {
183 set_service_path(network->service_path());
184 set_icon(chromeos::NetworkMenuIcon::GetImage(network,
185 chromeos::NetworkMenuIcon::COLOR_DARK));
186 set_name(network->name());
187 set_connecting(network->connecting());
188 set_connected(network->connected());
189 set_connectable(network->connectable());
190 set_connection_type(network->type());
191 set_remembered(false);
192 set_shared(false);
193 set_needs_new_plan(false);
194 set_policy_managed(network->ui_data().is_managed());
195 }
196
197 NetworkInfoDictionary::NetworkInfoDictionary(
198 const chromeos::Network* network,
199 const chromeos::Network* remembered,
200 float icon_scale)
201 : icon_scale_factor_(ui::GetScaleFactorFromScale(icon_scale)) {
202 set_service_path(remembered->service_path());
203 set_icon(chromeos::NetworkMenuIcon::GetImage(
204 network ? network : remembered, chromeos::NetworkMenuIcon::COLOR_DARK));
205 set_name(remembered->name());
206 set_connecting(network ? network->connecting() : false);
207 set_connected(network ? network->connected() : false);
208 set_connectable(true);
209 set_connection_type(remembered->type());
210 set_remembered(true);
211 set_shared(remembered->profile_type() == chromeos::PROFILE_SHARED);
212 set_needs_new_plan(false);
213 set_policy_managed(remembered->ui_data().is_managed());
214 }
215
216 DictionaryValue* NetworkInfoDictionary::BuildDictionary() {
217 std::string status;
218
219 if (remembered_) {
220 if (shared_)
221 status = l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SHARED_NETWORK);
222 } else {
223 // 802.1X networks can be connected but not have saved credentials, and
224 // hence be "not configured". Give preference to the "connected" and
225 // "connecting" states. http://crosbug.com/14459
226 int connection_state = IDS_STATUSBAR_NETWORK_DEVICE_DISCONNECTED;
227 if (connected_)
228 connection_state = IDS_STATUSBAR_NETWORK_DEVICE_CONNECTED;
229 else if (connecting_)
230 connection_state = IDS_STATUSBAR_NETWORK_DEVICE_CONNECTING;
231 else if (!connectable_)
232 connection_state = IDS_STATUSBAR_NETWORK_DEVICE_NOT_CONFIGURED;
233 status = l10n_util::GetStringUTF8(connection_state);
234 if (connection_type_ == chromeos::TYPE_CELLULAR) {
235 if (needs_new_plan_) {
236 status = l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_NO_PLAN_LABEL);
237 } else if (activation_state_ != chromeos::ACTIVATION_STATE_ACTIVATED) {
238 status.append(" / ");
239 status.append(chromeos::CellularNetwork::ActivationStateToString(
240 activation_state_));
241 }
242 }
243 }
244
245 scoped_ptr<DictionaryValue> network_info(new DictionaryValue());
246 network_info->SetInteger(kNetworkInfoKeyActivationState,
247 static_cast<int>(activation_state_));
248 network_info->SetBoolean(kNetworkInfoKeyConnectable, connectable_);
249 network_info->SetBoolean(kNetworkInfoKeyConnected, connected_);
250 network_info->SetBoolean(kNetworkInfoKeyConnecting, connecting_);
251 network_info->SetString(kNetworkInfoKeyIconURL, icon_url_);
252 network_info->SetBoolean(kNetworkInfoKeyNeedsNewPlan, needs_new_plan_);
253 network_info->SetString(kNetworkInfoKeyNetworkName, name_);
254 network_info->SetString(kNetworkInfoKeyNetworkStatus, status);
255 network_info->SetInteger(kNetworkInfoKeyNetworkType,
256 static_cast<int>(connection_type_));
257 network_info->SetBoolean(kNetworkInfoKeyRemembered, remembered_);
258 network_info->SetString(kNetworkInfoKeyServicePath, service_path_);
259 network_info->SetBoolean(kNetworkInfoKeyPolicyManaged, policy_managed_);
260 return network_info.release();
261 }
262
263 } // namespace
264
265 namespace options2 {
266
267 InternetOptionsHandler::InternetOptionsHandler()
268 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
269 registrar_.Add(this, chrome::NOTIFICATION_REQUIRE_PIN_SETTING_CHANGE_ENDED,
270 content::NotificationService::AllSources());
271 registrar_.Add(this, chrome::NOTIFICATION_ENTER_PIN_ENDED,
272 content::NotificationService::AllSources());
273 cros_ = chromeos::CrosLibrary::Get()->GetNetworkLibrary();
274 if (cros_) {
275 cros_->AddNetworkManagerObserver(this);
276 cros_->AddCellularDataPlanObserver(this);
277 MonitorNetworks();
278 }
279 }
280
281 InternetOptionsHandler::~InternetOptionsHandler() {
282 if (cros_) {
283 cros_->RemoveNetworkManagerObserver(this);
284 cros_->RemoveCellularDataPlanObserver(this);
285 cros_->RemoveObserverForAllNetworks(this);
286 }
287 }
288
289 void InternetOptionsHandler::GetLocalizedValues(
290 DictionaryValue* localized_strings) {
291 DCHECK(localized_strings);
292
293 static OptionsStringResource resources[] = {
294
295 // Main settings page.
296
297 { "ethernetTitle", IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET },
298 { "wifiTitle", IDS_OPTIONS_SETTINGS_SECTION_TITLE_WIFI_NETWORK },
299 // TODO(zelidrag): Change details title to Wimax once we get strings.
300 { "wimaxTitle", IDS_OPTIONS_SETTINGS_SECTION_TITLE_CELLULAR_NETWORK },
301 { "cellularTitle", IDS_OPTIONS_SETTINGS_SECTION_TITLE_CELLULAR_NETWORK },
302 { "vpnTitle", IDS_OPTIONS_SETTINGS_SECTION_TITLE_PRIVATE_NETWORK },
303 { "airplaneModeTitle", IDS_OPTIONS_SETTINGS_SECTION_TITLE_AIRPLANE_MODE },
304 { "airplaneModeLabel", IDS_OPTIONS_SETTINGS_NETWORK_AIRPLANE_MODE_LABEL },
305 { "networkNotConnected", IDS_OPTIONS_SETTINGS_NETWORK_NOT_CONNECTED },
306 { "networkConnected", IDS_CHROMEOS_NETWORK_STATE_READY },
307 { "joinOtherNetwork", IDS_OPTIONS_SETTINGS_NETWORK_OTHER },
308 { "networkOffline", IDS_OPTIONS_SETTINGS_NETWORK_OFFLINE },
309 { "networkDisabled", IDS_OPTIONS_SETTINGS_NETWORK_DISABLED },
310 { "networkOnline", IDS_OPTIONS_SETTINGS_NETWORK_ONLINE },
311 { "networkOptions", IDS_OPTIONS_SETTINGS_NETWORK_OPTIONS },
312 { "turnOffWifi", IDS_OPTIONS_SETTINGS_NETWORK_DISABLE_WIFI },
313 { "turnOffCellular", IDS_OPTIONS_SETTINGS_NETWORK_DISABLE_CELLULAR },
314 { "disconnectNetwork", IDS_OPTIONS_SETTINGS_DISCONNECT },
315 { "preferredNetworks", IDS_OPTIONS_SETTINGS_PREFERRED_NETWORKS_LABEL },
316 { "preferredNetworksPage", IDS_OPTIONS_SETTINGS_PREFERRED_NETWORKS_TITLE },
317 { "useSharedProxies", IDS_OPTIONS_SETTINGS_USE_SHARED_PROXIES },
318 { "addConnectionTitle",
319 IDS_OPTIONS_SETTINGS_SECTION_TITLE_ADD_CONNECTION },
320 { "addConnectionWifi", IDS_OPTIONS_SETTINGS_ADD_CONNECTION_WIFI },
321 { "addConnectionVPN", IDS_STATUSBAR_NETWORK_ADD_VPN },
322 { "enableDataRoaming", IDS_OPTIONS_SETTINGS_ENABLE_DATA_ROAMING },
323 { "disableDataRoaming", IDS_OPTIONS_SETTINGS_DISABLE_DATA_ROAMING },
324 { "dataRoamingDisableToggleTooltip",
325 IDS_OPTIONS_SETTINGS_TOGGLE_DATA_ROAMING_RESTRICTION },
326 { "activateNetwork", IDS_STATUSBAR_NETWORK_DEVICE_ACTIVATE },
327
328 // Internet details dialog.
329
330 { "changeProxyButton",
331 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CHANGE_PROXY_BUTTON },
332 { "managedNetwork", IDS_OPTIONS_SETTINGS_MANAGED_NETWORK },
333 { "wifiNetworkTabLabel", IDS_OPTIONS_SETTINGS_INTERNET_TAB_CONNECTION },
334 { "vpnTabLabel", IDS_OPTIONS_SETTINGS_INTERNET_TAB_VPN },
335 { "cellularPlanTabLabel", IDS_OPTIONS_SETTINGS_INTERNET_TAB_PLAN },
336 { "cellularConnTabLabel", IDS_OPTIONS_SETTINGS_INTERNET_TAB_CONNECTION },
337 { "cellularDeviceTabLabel", IDS_OPTIONS_SETTINGS_INTERNET_TAB_DEVICE },
338 { "networkTabLabel", IDS_OPTIONS_SETTINGS_INTERNET_TAB_NETWORK },
339 { "securityTabLabel", IDS_OPTIONS_SETTINGS_INTERNET_TAB_SECURITY },
340 { "proxyTabLabel", IDS_OPTIONS_SETTINGS_INTERNET_TAB_PROXY },
341 { "useDHCP", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_USE_DHCP },
342 { "useStaticIP", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_USE_STATIC_IP },
343 { "connectionState", IDS_OPTIONS_SETTINGS_INTERNET_CONNECTION_STATE },
344 { "inetAddress", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_ADDRESS },
345 { "inetSubnetAddress", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_SUBNETMASK },
346 { "inetGateway", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_GATEWAY },
347 { "inetDns", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_DNSSERVER },
348 { "hardwareAddress",
349 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_HARDWARE_ADDRESS },
350 { "detailsInternetDismiss", IDS_CLOSE },
351 { "activateButton", IDS_OPTIONS_SETTINGS_ACTIVATE },
352 { "buyplanButton", IDS_OPTIONS_SETTINGS_BUY_PLAN },
353 { "connectButton", IDS_OPTIONS_SETTINGS_CONNECT },
354 { "disconnectButton", IDS_OPTIONS_SETTINGS_DISCONNECT },
355 { "viewAccountButton", IDS_STATUSBAR_NETWORK_VIEW_ACCOUNT },
356
357 // TODO(zelidrag): Change details title to Wimax once we get strings.
358 { "wimaxConnTabLabel", IDS_OPTIONS_SETTINGS_INTERNET_TAB_CONNECTION },
359
360 // Wifi Tab.
361
362 { "accessLockedMsg", IDS_STATUSBAR_NETWORK_LOCKED },
363 { "inetSsid", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_NETWORK_ID },
364 { "inetBssid", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_NETWORK_BSSID },
365 { "inetEncryption",
366 IDS_OPTIONS_SETTIGNS_INTERNET_OPTIONS_NETWORK_ENCRYPTION },
367 { "inetFrequency",
368 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_NETWORK_FREQUENCY },
369 { "inetFrequencyFormat",
370 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_NETWORK_FREQUENCY_MHZ },
371 { "inetSignalStrength",
372 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_NETWORK_STRENGTH },
373 { "inetSignalStrengthFormat",
374 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_NETWORK_STRENGTH_PERCENTAGE },
375 { "inetPassProtected",
376 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_NET_PROTECTED },
377 { "inetNetworkShared",
378 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_NETWORK_SHARED },
379 { "inetPreferredNetwork",
380 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PREFER_NETWORK },
381 { "inetAutoConnectNetwork",
382 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_AUTO_CONNECT },
383 { "inetLogin", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_LOGIN },
384 { "inetShowPass", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_SHOWPASSWORD },
385 { "inetPassPrompt", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PASSWORD },
386 { "inetSsidPrompt", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_SSID },
387 { "inetStatus", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_STATUS_TITLE },
388 { "inetConnect", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CONNECT_TITLE },
389
390 // VPN Tab.
391
392 { "inetServiceName",
393 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVICE_NAME },
394 { "inetServerHostname",
395 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVER_HOSTNAME },
396 { "inetProviderType",
397 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_PROVIDER_TYPE },
398 { "inetUsername", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USERNAME },
399
400 // Cellular Tab.
401
402 { "serviceName", IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_SERVICE_NAME },
403 { "networkTechnology",
404 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_NETWORK_TECHNOLOGY },
405 { "operatorName", IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_OPERATOR },
406 { "operatorCode", IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_OPERATOR_CODE },
407 { "activationState",
408 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_ACTIVATION_STATE },
409 { "roamingState", IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_ROAMING_STATE },
410 { "restrictedPool",
411 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_RESTRICTED_POOL },
412 { "errorState", IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_ERROR_STATE },
413 { "manufacturer", IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_MANUFACTURER },
414 { "modelId", IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_MODEL_ID },
415 { "firmwareRevision",
416 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_FIRMWARE_REVISION },
417 { "hardwareRevision",
418 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_HARDWARE_REVISION },
419 { "prlVersion", IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_PRL_VERSION },
420 { "cellularApnLabel", IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_APN },
421 { "cellularApnOther", IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_APN_OTHER },
422 { "cellularApnUsername",
423 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_APN_USERNAME },
424 { "cellularApnPassword",
425 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_APN_PASSWORD },
426 { "cellularApnUseDefault",
427 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_APN_CLEAR },
428 { "cellularApnSet", IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_APN_SET },
429 { "cellularApnCancel", IDS_CANCEL },
430
431 // Security Tab.
432
433 { "accessSecurityTabLink",
434 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_ACCESS_SECURITY_TAB },
435 { "lockSimCard", IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_LOCK_SIM_CARD },
436 { "changePinButton",
437 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_BUTTON },
438
439 // Plan Tab.
440
441 { "planName", IDS_OPTIONS_SETTINGS_INTERNET_CELL_PLAN_NAME },
442 { "planLoading", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_LOADING_PLAN },
443 { "noPlansFound", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_NO_PLANS_FOUND },
444 { "purchaseMore", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PURCHASE_MORE },
445 { "dataRemaining", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_DATA_REMAINING },
446 { "planExpires", IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_EXPIRES },
447 { "showPlanNotifications",
448 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_SHOW_MOBILE_NOTIFICATION },
449 { "autoconnectCellular",
450 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_AUTO_CONNECT }
451 };
452
453 RegisterStrings(localized_strings, resources, arraysize(resources));
454
455 std::string owner;
456 chromeos::CrosSettings::Get()->GetString(chromeos::kDeviceOwner, &owner);
457 localized_strings->SetString("ownerUserId", UTF8ToUTF16(owner));
458
459 DictionaryValue* network_dictionary = new DictionaryValue;
460 FillNetworkInfo(network_dictionary);
461 localized_strings->Set("networkData", network_dictionary);
462 }
463
464 void InternetOptionsHandler::InitializePage() {
465 cros_->RequestNetworkScan();
466 }
467
468 void InternetOptionsHandler::RegisterMessages() {
469 // Setup handlers specific to this panel.
470 web_ui()->RegisterMessageCallback("networkCommand",
471 base::Bind(&InternetOptionsHandler::NetworkCommandCallback,
472 base::Unretained(this)));
473 web_ui()->RegisterMessageCallback("refreshNetworks",
474 base::Bind(&InternetOptionsHandler::RefreshNetworksCallback,
475 base::Unretained(this)));
476 web_ui()->RegisterMessageCallback("refreshCellularPlan",
477 base::Bind(&InternetOptionsHandler::RefreshCellularPlanCallback,
478 base::Unretained(this)));
479 web_ui()->RegisterMessageCallback("setPreferNetwork",
480 base::Bind(&InternetOptionsHandler::SetPreferNetworkCallback,
481 base::Unretained(this)));
482 web_ui()->RegisterMessageCallback("setAutoConnect",
483 base::Bind(&InternetOptionsHandler::SetAutoConnectCallback,
484 base::Unretained(this)));
485 web_ui()->RegisterMessageCallback("setIPConfig",
486 base::Bind(&InternetOptionsHandler::SetIPConfigCallback,
487 base::Unretained(this)));
488 web_ui()->RegisterMessageCallback("enableWifi",
489 base::Bind(&InternetOptionsHandler::EnableWifiCallback,
490 base::Unretained(this)));
491 web_ui()->RegisterMessageCallback("disableWifi",
492 base::Bind(&InternetOptionsHandler::DisableWifiCallback,
493 base::Unretained(this)));
494 web_ui()->RegisterMessageCallback("enableCellular",
495 base::Bind(&InternetOptionsHandler::EnableCellularCallback,
496 base::Unretained(this)));
497 web_ui()->RegisterMessageCallback("disableCellular",
498 base::Bind(&InternetOptionsHandler::DisableCellularCallback,
499 base::Unretained(this)));
500 web_ui()->RegisterMessageCallback("enableWimax",
501 base::Bind(&InternetOptionsHandler::EnableWimaxCallback,
502 base::Unretained(this)));
503 web_ui()->RegisterMessageCallback("disableWimax",
504 base::Bind(&InternetOptionsHandler::DisableWimaxCallback,
505 base::Unretained(this)));
506 web_ui()->RegisterMessageCallback("buyDataPlan",
507 base::Bind(&InternetOptionsHandler::BuyDataPlanCallback,
508 base::Unretained(this)));
509 web_ui()->RegisterMessageCallback("showMorePlanInfo",
510 base::Bind(&InternetOptionsHandler::ShowMorePlanInfoCallback,
511 base::Unretained(this)));
512 web_ui()->RegisterMessageCallback("setApn",
513 base::Bind(&InternetOptionsHandler::SetApnCallback,
514 base::Unretained(this)));
515 web_ui()->RegisterMessageCallback("setSimCardLock",
516 base::Bind(&InternetOptionsHandler::SetSimCardLockCallback,
517 base::Unretained(this)));
518 web_ui()->RegisterMessageCallback("changePin",
519 base::Bind(&InternetOptionsHandler::ChangePinCallback,
520 base::Unretained(this)));
521 web_ui()->RegisterMessageCallback("toggleAirplaneMode",
522 base::Bind(&InternetOptionsHandler::ToggleAirplaneModeCallback,
523 base::Unretained(this)));
524 }
525
526 void InternetOptionsHandler::EnableWifiCallback(const ListValue* args) {
527 cros_->EnableWifiNetworkDevice(true);
528 }
529
530 void InternetOptionsHandler::DisableWifiCallback(const ListValue* args) {
531 cros_->EnableWifiNetworkDevice(false);
532 }
533
534 void InternetOptionsHandler::EnableCellularCallback(const ListValue* args) {
535 // TODO(nkostylev): Code duplication, see NetworkMenu::ToggleCellular().
536 const chromeos::NetworkDevice* mobile = cros_->FindMobileDevice();
537 if (!mobile) {
538 LOG(ERROR) << "Didn't find mobile device, it should have been available.";
539 cros_->EnableCellularNetworkDevice(true);
540 } else if (!mobile->is_sim_locked()) {
541 if (mobile->is_sim_absent()) {
542 std::string setup_url;
543 chromeos::MobileConfig* config = chromeos::MobileConfig::GetInstance();
544 if (config->IsReady()) {
545 const chromeos::MobileConfig::LocaleConfig* locale_config =
546 config->GetLocaleConfig();
547 if (locale_config)
548 setup_url = locale_config->setup_url();
549 }
550 if (!setup_url.empty()) {
551 chrome::ShowSingletonTab(GetAppropriateBrowser(), GURL(setup_url));
552 } else {
553 // TODO(nkostylev): Show generic error message. http://crosbug.com/15444
554 }
555 } else {
556 cros_->EnableCellularNetworkDevice(true);
557 }
558 } else {
559 chromeos::SimDialogDelegate::ShowDialog(GetNativeWindow(),
560 chromeos::SimDialogDelegate::SIM_DIALOG_UNLOCK);
561 }
562 }
563
564 void InternetOptionsHandler::DisableCellularCallback(const ListValue* args) {
565 cros_->EnableCellularNetworkDevice(false);
566 }
567
568 void InternetOptionsHandler::EnableWimaxCallback(const ListValue* args) {
569 cros_->EnableWimaxNetworkDevice(true);
570 }
571
572 void InternetOptionsHandler::DisableWimaxCallback(const ListValue* args) {
573 cros_->EnableWimaxNetworkDevice(false);
574 }
575
576 void InternetOptionsHandler::ShowMorePlanInfoCallback(const ListValue* args) {
577 if (!web_ui())
578 return;
579
580 const chromeos::CellularNetwork* cellular = cros_->cellular_network();
581 if (!cellular)
582 return;
583
584 web_ui()->GetWebContents()->OpenURL(content::OpenURLParams(
585 cellular->GetAccountInfoUrl(), content::Referrer(),
586 NEW_FOREGROUND_TAB,
587 content::PAGE_TRANSITION_LINK, false));
588 }
589
590 void InternetOptionsHandler::BuyDataPlanCallback(const ListValue* args) {
591 if (!web_ui())
592 return;
593
594 std::string service_path;
595 if (args->GetSize() != 1 || !args->GetString(0, &service_path)) {
596 NOTREACHED();
597 return;
598 }
599 ash::Shell::GetInstance()->delegate()->OpenMobileSetup(service_path);
600 }
601
602 void InternetOptionsHandler::SetApnCallback(const ListValue* args) {
603 std::string service_path;
604 std::string apn;
605 std::string username;
606 std::string password;
607 if (args->GetSize() != 4 ||
608 !args->GetString(0, &service_path) ||
609 !args->GetString(1, &apn) ||
610 !args->GetString(2, &username) ||
611 !args->GetString(3, &password)) {
612 NOTREACHED();
613 return;
614 }
615
616 chromeos::CellularNetwork* network =
617 cros_->FindCellularNetworkByPath(service_path);
618 if (network) {
619 network->SetApn(chromeos::CellularApn(
620 apn, network->apn().network_id, username, password));
621 }
622 }
623
624 void InternetOptionsHandler::SetSimCardLockCallback(const ListValue* args) {
625 bool require_pin_new_value;
626 if (!args->GetBoolean(0, &require_pin_new_value)) {
627 NOTREACHED();
628 return;
629 }
630 // 1. Bring up SIM unlock dialog, pass new RequirePin setting in URL.
631 // 2. Dialog will ask for current PIN in any case.
632 // 3. If card is locked it will first call PIN unlock operation
633 // 4. Then it will call Set RequirePin, passing the same PIN.
634 // 5. We'll get notified by REQUIRE_PIN_SETTING_CHANGE_ENDED notification.
635 chromeos::SimDialogDelegate::SimDialogMode mode;
636 if (require_pin_new_value)
637 mode = chromeos::SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON;
638 else
639 mode = chromeos::SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF;
640 chromeos::SimDialogDelegate::ShowDialog(GetNativeWindow(), mode);
641 }
642
643 void InternetOptionsHandler::ChangePinCallback(const ListValue* args) {
644 chromeos::SimDialogDelegate::ShowDialog(GetNativeWindow(),
645 chromeos::SimDialogDelegate::SIM_DIALOG_CHANGE_PIN);
646 }
647
648 void InternetOptionsHandler::RefreshNetworksCallback(const ListValue* args) {
649 cros_->RequestNetworkScan();
650 }
651
652 void InternetOptionsHandler::RefreshNetworkData() {
653 DictionaryValue dictionary;
654 FillNetworkInfo(&dictionary);
655 web_ui()->CallJavascriptFunction(
656 "options.network.NetworkList.refreshNetworkData", dictionary);
657 }
658
659 void InternetOptionsHandler::OnNetworkManagerChanged(
660 chromeos::NetworkLibrary* cros) {
661 if (!web_ui())
662 return;
663 MonitorNetworks();
664 RefreshNetworkData();
665 }
666
667 void InternetOptionsHandler::OnNetworkChanged(
668 chromeos::NetworkLibrary* cros,
669 const chromeos::Network* network) {
670 if (web_ui())
671 RefreshNetworkData();
672 }
673
674 // Monitor wireless networks for changes. It is only necessary
675 // to set up individual observers for the cellular networks
676 // (if any) and for the connected Wi-Fi network (if any). The
677 // only change we are interested in for Wi-Fi networks is signal
678 // strength. For non-connected Wi-Fi networks, all information is
679 // reported via scan results, which trigger network manager
680 // updates. Only the connected Wi-Fi network has changes reported
681 // via service property updates.
682 void InternetOptionsHandler::MonitorNetworks() {
683 cros_->RemoveObserverForAllNetworks(this);
684 const chromeos::WifiNetwork* wifi_network = cros_->wifi_network();
685 if (wifi_network)
686 cros_->AddNetworkObserver(wifi_network->service_path(), this);
687
688 // Always monitor all mobile networks, if any, so that changes
689 // in network technology, roaming status, and signal strength
690 // will be shown.
691 const chromeos::WimaxNetworkVector& wimax_networks =
692 cros_->wimax_networks();
693 for (size_t i = 0; i < wimax_networks.size(); ++i) {
694 chromeos::WimaxNetwork* wimax_network = wimax_networks[i];
695 cros_->AddNetworkObserver(wimax_network->service_path(), this);
696 }
697 const chromeos::CellularNetworkVector& cell_networks =
698 cros_->cellular_networks();
699 for (size_t i = 0; i < cell_networks.size(); ++i) {
700 chromeos::CellularNetwork* cell_network = cell_networks[i];
701 cros_->AddNetworkObserver(cell_network->service_path(), this);
702 }
703 const chromeos::VirtualNetwork* virtual_network = cros_->virtual_network();
704 if (virtual_network)
705 cros_->AddNetworkObserver(virtual_network->service_path(), this);
706 }
707
708 void InternetOptionsHandler::OnCellularDataPlanChanged(
709 chromeos::NetworkLibrary* cros) {
710 if (!web_ui())
711 return;
712 const chromeos::CellularNetwork* cellular = cros_->cellular_network();
713 if (!cellular)
714 return;
715 const chromeos::CellularDataPlanVector* plans =
716 cros_->GetDataPlans(cellular->service_path());
717 DictionaryValue connection_plans;
718 ListValue* plan_list = new ListValue();
719 if (plans) {
720 for (chromeos::CellularDataPlanVector::const_iterator iter = plans->begin();
721 iter != plans->end(); ++iter) {
722 plan_list->Append(CellularDataPlanToDictionary(*iter));
723 }
724 }
725 connection_plans.SetString("servicePath", cellular->service_path());
726 connection_plans.SetBoolean("needsPlan", cellular->needs_new_plan());
727 connection_plans.SetBoolean("activated",
728 cellular->activation_state() == chromeos::ACTIVATION_STATE_ACTIVATED);
729 connection_plans.Set("plans", plan_list);
730 SetActivationButtonVisibility(cellular,
731 &connection_plans,
732 cros_->GetCellularHomeCarrierId());
733 web_ui()->CallJavascriptFunction(
734 "options.internet.DetailsInternetPage.updateCellularPlans",
735 connection_plans);
736 }
737
738
739 void InternetOptionsHandler::Observe(
740 int type,
741 const content::NotificationSource& source,
742 const content::NotificationDetails& details) {
743 OptionsPageUIHandler::Observe(type, source, details);
744 if (type == chrome::NOTIFICATION_REQUIRE_PIN_SETTING_CHANGE_ENDED) {
745 base::FundamentalValue require_pin(*content::Details<bool>(details).ptr());
746 web_ui()->CallJavascriptFunction(
747 "options.internet.DetailsInternetPage.updateSecurityTab", require_pin);
748 } else if (type == chrome::NOTIFICATION_ENTER_PIN_ENDED) {
749 // We make an assumption (which is valid for now) that the SIM
750 // unlock dialog is put up only when the user is trying to enable
751 // mobile data.
752 bool cancelled = *content::Details<bool>(details).ptr();
753 if (cancelled)
754 RefreshNetworkData();
755 // The case in which the correct PIN was entered and the SIM is
756 // now unlocked is handled in NetworkMenuButton.
757 }
758 }
759
760 DictionaryValue* InternetOptionsHandler::CellularDataPlanToDictionary(
761 const chromeos::CellularDataPlan* plan) {
762 DictionaryValue* plan_dict = new DictionaryValue();
763 plan_dict->SetInteger("planType", plan->plan_type);
764 plan_dict->SetString("name", plan->plan_name);
765 plan_dict->SetString("planSummary", plan->GetPlanDesciption());
766 plan_dict->SetString("dataRemaining", plan->GetDataRemainingDesciption());
767 plan_dict->SetString("planExpires", plan->GetPlanExpiration());
768 plan_dict->SetString("warning", plan->GetRemainingWarning());
769 return plan_dict;
770 }
771
772 void InternetOptionsHandler::SetPreferNetworkCallback(const ListValue* args) {
773 std::string service_path;
774 std::string prefer_network_str;
775
776 if (args->GetSize() < 2 ||
777 !args->GetString(0, &service_path) ||
778 !args->GetString(1, &prefer_network_str)) {
779 NOTREACHED();
780 return;
781 }
782
783 chromeos::Network* network = cros_->FindNetworkByPath(service_path);
784 if (!network)
785 return;
786
787 bool prefer_network = prefer_network_str == "true";
788 if (prefer_network != network->preferred())
789 network->SetPreferred(prefer_network);
790 }
791
792 void InternetOptionsHandler::SetAutoConnectCallback(const ListValue* args) {
793 std::string service_path;
794 std::string auto_connect_str;
795
796 if (args->GetSize() < 2 ||
797 !args->GetString(0, &service_path) ||
798 !args->GetString(1, &auto_connect_str)) {
799 NOTREACHED();
800 return;
801 }
802
803 chromeos::Network* network = cros_->FindNetworkByPath(service_path);
804 if (!network)
805 return;
806
807 bool auto_connect = auto_connect_str == "true";
808 if (auto_connect != network->auto_connect())
809 network->SetAutoConnect(auto_connect);
810 }
811
812 void InternetOptionsHandler::SetIPConfigCallback(const ListValue* args) {
813 std::string service_path;
814 std::string dhcp_str;
815 std::string address;
816 std::string netmask;
817 std::string gateway;
818 std::string name_servers;
819
820 if (args->GetSize() < 6 ||
821 !args->GetString(0, &service_path) ||
822 !args->GetString(1, &dhcp_str) ||
823 !args->GetString(2, &address) ||
824 !args->GetString(3, &netmask) ||
825 !args->GetString(4, &gateway) ||
826 !args->GetString(5, &name_servers)) {
827 NOTREACHED();
828 return;
829 }
830
831 chromeos::Network* network = cros_->FindNetworkByPath(service_path);
832 if (!network)
833 return;
834
835 cros_->SetIPConfig(chromeos::NetworkIPConfig(network->device_path(),
836 dhcp_str == "true" ? chromeos::IPCONFIG_TYPE_DHCP :
837 chromeos::IPCONFIG_TYPE_IPV4,
838 address, netmask, gateway, name_servers));
839 }
840
841 void InternetOptionsHandler::PopulateDictionaryDetails(
842 const chromeos::Network* network) {
843 DCHECK(network);
844
845 if (web_ui()) {
846 Profile::FromWebUI(web_ui())->GetProxyConfigTracker()->UISetCurrentNetwork(
847 network->service_path());
848 }
849
850 const chromeos::NetworkUIData& ui_data = network->ui_data();
851 const base::DictionaryValue* onc =
852 cros_->FindOncForNetwork(network->unique_id());
853
854 DictionaryValue dictionary;
855 std::string hardware_address;
856 chromeos::NetworkIPConfigVector ipconfigs = cros_->GetIPConfigs(
857 network->device_path(), &hardware_address,
858 chromeos::NetworkLibrary::FORMAT_COLON_SEPARATED_HEX);
859 if (!hardware_address.empty())
860 dictionary.SetString("hardwareAddress", hardware_address);
861
862 scoped_ptr<DictionaryValue> ipconfig_dhcp;
863 scoped_ptr<DictionaryValue> ipconfig_static;
864 for (chromeos::NetworkIPConfigVector::const_iterator it = ipconfigs.begin();
865 it != ipconfigs.end(); ++it) {
866 const chromeos::NetworkIPConfig& ipconfig = *it;
867 scoped_ptr<DictionaryValue> ipconfig_dict(new DictionaryValue());
868 ipconfig_dict->SetString("address", ipconfig.address);
869 ipconfig_dict->SetString("subnetAddress", ipconfig.netmask);
870 ipconfig_dict->SetString("gateway", ipconfig.gateway);
871 ipconfig_dict->SetString("dns", ipconfig.name_servers);
872 if (ipconfig.type == chromeos::IPCONFIG_TYPE_DHCP)
873 ipconfig_dhcp.reset(ipconfig_dict.release());
874 else if (ipconfig.type == chromeos::IPCONFIG_TYPE_IPV4)
875 ipconfig_static.reset(ipconfig_dict.release());
876 }
877
878 chromeos::NetworkPropertyUIData ipconfig_dhcp_ui_data(ui_data);
879 SetValueDictionary(&dictionary, "ipconfigDHCP", ipconfig_dhcp.release(),
880 ipconfig_dhcp_ui_data);
881 chromeos::NetworkPropertyUIData ipconfig_static_ui_data(ui_data);
882 SetValueDictionary(&dictionary, "ipconfigStatic", ipconfig_static.release(),
883 ipconfig_static_ui_data);
884
885 chromeos::ConnectionType type = network->type();
886 dictionary.SetInteger("type", type);
887 dictionary.SetString("servicePath", network->service_path());
888 dictionary.SetBoolean("connecting", network->connecting());
889 dictionary.SetBoolean("connected", network->connected());
890 dictionary.SetString("connectionState", network->GetStateString());
891 dictionary.SetString("networkName", network->name());
892
893 // Only show proxy for remembered networks.
894 chromeos::NetworkProfileType network_profile = network->profile_type();
895 dictionary.SetBoolean("showProxy", network_profile != chromeos::PROFILE_NONE);
896
897 // Enable static ip config for ethernet. For wifi, enable if flag is set.
898 bool staticIPConfig = type == chromeos::TYPE_ETHERNET ||
899 (type == chromeos::TYPE_WIFI &&
900 CommandLine::ForCurrentProcess()->HasSwitch(
901 switches::kEnableStaticIPConfig));
902 dictionary.SetBoolean("showStaticIPConfig", staticIPConfig);
903
904 chromeos::NetworkPropertyUIData preferred_ui_data(ui_data);
905 if (network_profile == chromeos::PROFILE_USER) {
906 dictionary.SetBoolean("showPreferred", true);
907 SetValueDictionary(&dictionary, "preferred",
908 Value::CreateBooleanValue(network->preferred()),
909 preferred_ui_data);
910 } else {
911 dictionary.SetBoolean("showPreferred", false);
912 SetValueDictionary(&dictionary, "preferred",
913 Value::CreateBooleanValue(network->preferred()),
914 preferred_ui_data);
915 }
916 chromeos::NetworkPropertyUIData auto_connect_ui_data(ui_data);
917 if (type == chromeos::TYPE_WIFI) {
918 auto_connect_ui_data.ParseOncProperty(
919 ui_data, onc,
920 base::StringPrintf("%s.%s",
921 chromeos::onc::kWiFi,
922 chromeos::onc::wifi::kAutoConnect));
923 }
924 SetValueDictionary(&dictionary, "autoConnect",
925 Value::CreateBooleanValue(network->auto_connect()),
926 auto_connect_ui_data);
927
928 if (type == chromeos::TYPE_WIFI) {
929 dictionary.SetBoolean("deviceConnected", cros_->wifi_connected());
930 const chromeos::WifiNetwork* wifi =
931 cros_->FindWifiNetworkByPath(network->service_path());
932 if (!wifi) {
933 LOG(WARNING) << "Cannot find network " << network->service_path();
934 } else {
935 PopulateWifiDetails(wifi, &dictionary);
936 }
937 } else if (type == chromeos::TYPE_WIMAX) {
938 dictionary.SetBoolean("deviceConnected", cros_->wimax_connected());
939 const chromeos::WimaxNetwork* wimax =
940 cros_->FindWimaxNetworkByPath(network->service_path());
941 if (!wimax) {
942 LOG(WARNING) << "Cannot find network " << network->service_path();
943 } else {
944 PopulateWimaxDetails(wimax, &dictionary);
945 }
946 } else if (type == chromeos::TYPE_CELLULAR) {
947 dictionary.SetBoolean("deviceConnected", cros_->cellular_connected());
948 const chromeos::CellularNetwork* cellular =
949 cros_->FindCellularNetworkByPath(network->service_path());
950 if (!cellular) {
951 LOG(WARNING) << "Cannot find network " << network->service_path();
952 } else {
953 PopulateCellularDetails(cellular, &dictionary);
954 }
955 } else if (type == chromeos::TYPE_VPN) {
956 dictionary.SetBoolean("deviceConnected",
957 cros_->virtual_network_connected());
958 const chromeos::VirtualNetwork* vpn =
959 cros_->FindVirtualNetworkByPath(network->service_path());
960 if (!vpn) {
961 LOG(WARNING) << "Cannot find network " << network->service_path();
962 } else {
963 PopulateVPNDetails(vpn, &dictionary);
964 }
965 } else if (type == chromeos::TYPE_ETHERNET) {
966 dictionary.SetBoolean("deviceConnected", cros_->ethernet_connected());
967 }
968
969 web_ui()->CallJavascriptFunction(
970 "options.internet.DetailsInternetPage.showDetailedInfo", dictionary);
971 }
972
973 void InternetOptionsHandler::PopulateWifiDetails(
974 const chromeos::WifiNetwork* wifi,
975 DictionaryValue* dictionary) {
976 dictionary->SetString("ssid", wifi->name());
977 bool remembered = (wifi->profile_type() != chromeos::PROFILE_NONE);
978 dictionary->SetBoolean("remembered", remembered);
979 bool shared = wifi->profile_type() == chromeos::PROFILE_SHARED;
980 dictionary->SetBoolean("shared", shared);
981 dictionary->SetString("encryption", wifi->GetEncryptionString());
982 dictionary->SetString("bssid", wifi->bssid());
983 dictionary->SetInteger("frequency", wifi->frequency());
984 dictionary->SetInteger("strength", wifi->strength());
985 }
986
987 void InternetOptionsHandler::PopulateWimaxDetails(
988 const chromeos::WimaxNetwork* wimax,
989 DictionaryValue* dictionary) {
990 bool remembered = (wimax->profile_type() != chromeos::PROFILE_NONE);
991 dictionary->SetBoolean("remembered", remembered);
992 bool shared = wimax->profile_type() == chromeos::PROFILE_SHARED;
993 dictionary->SetBoolean("shared", shared);
994 if (wimax->passphrase_required())
995 dictionary->SetString("identity", wimax->eap_identity());
996
997 dictionary->SetInteger("strength", wimax->strength());
998 }
999
1000 DictionaryValue* InternetOptionsHandler::CreateDictionaryFromCellularApn(
1001 const chromeos::CellularApn& apn) {
1002 DictionaryValue* dictionary = new DictionaryValue();
1003 dictionary->SetString("apn", apn.apn);
1004 dictionary->SetString("networkId", apn.network_id);
1005 dictionary->SetString("username", apn.username);
1006 dictionary->SetString("password", apn.password);
1007 dictionary->SetString("name", apn.name);
1008 dictionary->SetString("localizedName", apn.localized_name);
1009 dictionary->SetString("language", apn.language);
1010 return dictionary;
1011 }
1012
1013 void InternetOptionsHandler::PopulateCellularDetails(
1014 const chromeos::CellularNetwork* cellular,
1015 DictionaryValue* dictionary) {
1016 // Cellular network / connection settings.
1017 dictionary->SetString("serviceName", cellular->name());
1018 dictionary->SetString("networkTechnology",
1019 cellular->GetNetworkTechnologyString());
1020 dictionary->SetString("operatorName", cellular->operator_name());
1021 dictionary->SetString("operatorCode", cellular->operator_code());
1022 dictionary->SetString("activationState",
1023 cellular->GetActivationStateString());
1024 dictionary->SetString("roamingState",
1025 cellular->GetRoamingStateString());
1026 dictionary->SetString("restrictedPool",
1027 cellular->restricted_pool() ?
1028 l10n_util::GetStringUTF8(
1029 IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL) :
1030 l10n_util::GetStringUTF8(
1031 IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL));
1032 dictionary->SetString("errorState", cellular->GetErrorString());
1033 dictionary->SetString("supportUrl", cellular->payment_url());
1034 dictionary->SetBoolean("needsPlan", cellular->needs_new_plan());
1035
1036 dictionary->Set("apn", CreateDictionaryFromCellularApn(cellular->apn()));
1037 dictionary->Set("lastGoodApn",
1038 CreateDictionaryFromCellularApn(cellular->last_good_apn()));
1039
1040 // Device settings.
1041 const chromeos::NetworkDevice* device =
1042 cros_->FindNetworkDeviceByPath(cellular->device_path());
1043 if (device) {
1044 chromeos::NetworkPropertyUIData cellular_propety_ui_data(
1045 cellular->ui_data());
1046 dictionary->SetString("manufacturer", device->manufacturer());
1047 dictionary->SetString("modelId", device->model_id());
1048 dictionary->SetString("firmwareRevision", device->firmware_revision());
1049 dictionary->SetString("hardwareRevision", device->hardware_revision());
1050 dictionary->SetString("prlVersion",
1051 base::StringPrintf("%u", device->prl_version()));
1052 dictionary->SetString("meid", device->meid());
1053 dictionary->SetString("imei", device->imei());
1054 dictionary->SetString("mdn", device->mdn());
1055 dictionary->SetString("imsi", device->imsi());
1056 dictionary->SetString("esn", device->esn());
1057 dictionary->SetString("min", device->min());
1058 dictionary->SetBoolean("gsm",
1059 device->technology_family() == chromeos::TECHNOLOGY_FAMILY_GSM);
1060 SetValueDictionary(
1061 dictionary, "simCardLockEnabled",
1062 Value::CreateBooleanValue(
1063 device->sim_pin_required() == chromeos::SIM_PIN_REQUIRED),
1064 cellular_propety_ui_data);
1065
1066 chromeos::MobileConfig* config = chromeos::MobileConfig::GetInstance();
1067 if (config->IsReady()) {
1068 const std::string& carrier_id = cros_->GetCellularHomeCarrierId();
1069 const chromeos::MobileConfig::Carrier* carrier =
1070 config->GetCarrier(carrier_id);
1071 if (carrier && !carrier->top_up_url().empty())
1072 dictionary->SetString("carrierUrl", carrier->top_up_url());
1073 }
1074
1075 const chromeos::CellularApnList& apn_list = device->provider_apn_list();
1076 ListValue* apn_list_value = new ListValue();
1077 for (chromeos::CellularApnList::const_iterator it = apn_list.begin();
1078 it != apn_list.end(); ++it) {
1079 apn_list_value->Append(CreateDictionaryFromCellularApn(*it));
1080 }
1081 SetValueDictionary(dictionary, "providerApnList", apn_list_value,
1082 cellular_propety_ui_data);
1083 }
1084
1085 SetActivationButtonVisibility(cellular,
1086 dictionary,
1087 cros_->GetCellularHomeCarrierId());
1088 }
1089
1090 void InternetOptionsHandler::PopulateVPNDetails(
1091 const chromeos::VirtualNetwork* vpn,
1092 DictionaryValue* dictionary) {
1093 dictionary->SetString("service_name", vpn->name());
1094 bool remembered = (vpn->profile_type() != chromeos::PROFILE_NONE);
1095 dictionary->SetBoolean("remembered", remembered);
1096 dictionary->SetString("server_hostname", vpn->server_hostname());
1097 dictionary->SetString("provider_type", vpn->GetProviderTypeString());
1098 dictionary->SetString("username", vpn->username());
1099 }
1100
1101 void InternetOptionsHandler::SetActivationButtonVisibility(
1102 const chromeos::CellularNetwork* cellular,
1103 DictionaryValue* dictionary,
1104 const std::string& carrier_id) {
1105 if (cellular->needs_new_plan()) {
1106 dictionary->SetBoolean("showBuyButton", true);
1107 } else if (cellular->activation_state() !=
1108 chromeos::ACTIVATION_STATE_ACTIVATING &&
1109 cellular->activation_state() !=
1110 chromeos::ACTIVATION_STATE_ACTIVATED) {
1111 dictionary->SetBoolean("showActivateButton", true);
1112 } else {
1113 const chromeos::MobileConfig::Carrier* carrier =
1114 chromeos::MobileConfig::GetInstance()->GetCarrier(carrier_id);
1115 if (carrier && carrier->show_portal_button()) {
1116 // This will trigger BuyDataPlanCallback() so that
1117 // chrome://mobilesetup/ will open carrier specific portal.
1118 dictionary->SetBoolean("showViewAccountButton", true);
1119 }
1120 }
1121 }
1122
1123 gfx::NativeWindow InternetOptionsHandler::GetNativeWindow() const {
1124 // TODO(beng): This is an improper direct dependency on Browser. Route this
1125 // through some sort of delegate.
1126 Browser* browser =
1127 browser::FindBrowserWithProfile(Profile::FromWebUI(web_ui()));
1128 return browser->window()->GetNativeWindow();
1129 }
1130
1131 Browser* InternetOptionsHandler::GetAppropriateBrowser() {
1132 return browser::FindOrCreateTabbedBrowser(
1133 ProfileManager::GetDefaultProfileOrOffTheRecord());
1134 }
1135
1136 void InternetOptionsHandler::NetworkCommandCallback(const ListValue* args) {
1137 std::string str_type;
1138 std::string service_path;
1139 std::string command;
1140 if (args->GetSize() != 3 ||
1141 !args->GetString(0, &str_type) ||
1142 !args->GetString(1, &service_path) ||
1143 !args->GetString(2, &command)) {
1144 NOTREACHED();
1145 return;
1146 }
1147
1148 int type = atoi(str_type.c_str());
1149 if (type == chromeos::TYPE_ETHERNET) {
1150 const chromeos::EthernetNetwork* ether = cros_->ethernet_network();
1151 if (ether)
1152 PopulateDictionaryDetails(ether);
1153 } else if (type == chromeos::TYPE_WIFI) {
1154 HandleWifiButtonClick(service_path, command);
1155 } else if (type == chromeos::TYPE_WIMAX) {
1156 HandleWimaxButtonClick(service_path, command);
1157 } else if (type == chromeos::TYPE_CELLULAR) {
1158 HandleCellularButtonClick(service_path, command);
1159 } else if (type == chromeos::TYPE_VPN) {
1160 HandleVPNButtonClick(service_path, command);
1161 } else {
1162 NOTREACHED();
1163 }
1164 }
1165
1166 void InternetOptionsHandler::ToggleAirplaneModeCallback(const ListValue* args) {
1167 // TODO(kevers): The use of 'offline_mode' is not quite correct. Update once
1168 // we have proper back-end support.
1169 cros_->EnableOfflineMode(!cros_->offline_mode());
1170 }
1171
1172 void InternetOptionsHandler::HandleWifiButtonClick(
1173 const std::string& service_path,
1174 const std::string& command) {
1175 chromeos::WifiNetwork* wifi = NULL;
1176 if (command == "forget") {
1177 cros_->ForgetNetwork(service_path);
1178 } else if (service_path == kOtherNetworksFakePath) {
1179 // Other wifi networks.
1180 chromeos::NetworkConfigView::ShowForType(
1181 chromeos::TYPE_WIFI, GetNativeWindow());
1182 } else if ((wifi = cros_->FindWifiNetworkByPath(service_path))) {
1183 if (command == "connect") {
1184 wifi->SetEnrollmentDelegate(
1185 chromeos::CreateEnrollmentDelegate(GetNativeWindow(), wifi->name(),
1186 ProfileManager::GetLastUsedProfile()));
1187 wifi->AttemptConnection(base::Bind(&InternetOptionsHandler::DoConnect,
1188 weak_factory_.GetWeakPtr(),
1189 wifi));
1190 } else if (command == "disconnect") {
1191 cros_->DisconnectFromNetwork(wifi);
1192 } else if (command == "options") {
1193 PopulateDictionaryDetails(wifi);
1194 }
1195 }
1196 }
1197
1198 void InternetOptionsHandler::HandleWimaxButtonClick(
1199 const std::string& service_path,
1200 const std::string& command) {
1201 chromeos::WimaxNetwork* wimax = NULL;
1202 if (command == "forget") {
1203 cros_->ForgetNetwork(service_path);
1204 } else if ((wimax = cros_->FindWimaxNetworkByPath(service_path))) {
1205 if (command == "connect") {
1206 wimax->SetEnrollmentDelegate(
1207 chromeos::CreateEnrollmentDelegate(GetNativeWindow(), wimax->name(),
1208 ProfileManager::GetLastUsedProfile()));
1209 wimax->AttemptConnection(base::Bind(&InternetOptionsHandler::DoConnect,
1210 weak_factory_.GetWeakPtr(),
1211 wimax));
1212 } else if (command == "disconnect") {
1213 cros_->DisconnectFromNetwork(wimax);
1214 } else if (command == "options") {
1215 PopulateDictionaryDetails(wimax);
1216 }
1217 }
1218 }
1219
1220 void InternetOptionsHandler::HandleCellularButtonClick(
1221 const std::string& service_path,
1222 const std::string& command) {
1223 chromeos::CellularNetwork* cellular = NULL;
1224 if (service_path == kOtherNetworksFakePath) {
1225 chromeos::ChooseMobileNetworkDialog::ShowDialog(GetNativeWindow());
1226 } else if ((cellular = cros_->FindCellularNetworkByPath(service_path))) {
1227 if (command == "connect") {
1228 cros_->ConnectToCellularNetwork(cellular);
1229 } else if (command == "disconnect") {
1230 cros_->DisconnectFromNetwork(cellular);
1231 } else if (command == "activate") {
1232 ash::Shell::GetInstance()->delegate()->OpenMobileSetup(service_path);
1233 } else if (command == "options") {
1234 PopulateDictionaryDetails(cellular);
1235 }
1236 }
1237 }
1238
1239 void InternetOptionsHandler::HandleVPNButtonClick(
1240 const std::string& service_path,
1241 const std::string& command) {
1242 chromeos::VirtualNetwork* network = NULL;
1243 if (command == "forget") {
1244 cros_->ForgetNetwork(service_path);
1245 } else if (service_path == kOtherNetworksFakePath) {
1246 // TODO(altimofeev): verify if service_path in condition is correct.
1247 // Other VPN networks.
1248 chromeos::NetworkConfigView::ShowForType(
1249 chromeos::TYPE_VPN, GetNativeWindow());
1250 } else if ((network = cros_->FindVirtualNetworkByPath(service_path))) {
1251 if (command == "connect") {
1252 network->SetEnrollmentDelegate(
1253 chromeos::CreateEnrollmentDelegate(
1254 GetNativeWindow(),
1255 network->name(),
1256 ProfileManager::GetLastUsedProfile()));
1257 network->AttemptConnection(base::Bind(&InternetOptionsHandler::DoConnect,
1258 weak_factory_.GetWeakPtr(),
1259 network));
1260 } else if (command == "disconnect") {
1261 cros_->DisconnectFromNetwork(network);
1262 } else if (command == "options") {
1263 PopulateDictionaryDetails(network);
1264 }
1265 }
1266 }
1267
1268 void InternetOptionsHandler::DoConnect(chromeos::Network* network) {
1269 if (network->type() == chromeos::TYPE_VPN) {
1270 chromeos::VirtualNetwork* vpn =
1271 static_cast<chromeos::VirtualNetwork*>(network);
1272 if (vpn->NeedMoreInfoToConnect()) {
1273 chromeos::NetworkConfigView::Show(network, GetNativeWindow());
1274 } else {
1275 cros_->ConnectToVirtualNetwork(vpn);
1276 // Connection failures are responsible for updating the UI, including
1277 // reopening dialogs.
1278 }
1279 } else if (network->type() == chromeos::TYPE_WIFI) {
1280 chromeos::WifiNetwork* wifi = static_cast<chromeos::WifiNetwork*>(network);
1281 if (wifi->IsPassphraseRequired()) {
1282 // Show the connection UI if we require a passphrase.
1283 chromeos::NetworkConfigView::Show(wifi, GetNativeWindow());
1284 } else {
1285 cros_->ConnectToWifiNetwork(wifi);
1286 // Connection failures are responsible for updating the UI, including
1287 // reopening dialogs.
1288 }
1289 } else if (network->type() == chromeos::TYPE_WIMAX) {
1290 chromeos::WimaxNetwork* wimax =
1291 static_cast<chromeos::WimaxNetwork*>(network);
1292 if (wimax->passphrase_required()) {
1293 // Show the connection UI if we require a passphrase.
1294 // TODO(stavenjb): Implament WiMAX connection UI.
1295 chromeos::NetworkConfigView::Show(wimax, GetNativeWindow());
1296 } else {
1297 cros_->ConnectToWimaxNetwork(wimax);
1298 // Connection failures are responsible for updating the UI, including
1299 // reopening dialogs.
1300 }
1301 }
1302 }
1303
1304 void InternetOptionsHandler::RefreshCellularPlanCallback(
1305 const ListValue* args) {
1306 std::string service_path;
1307 if (args->GetSize() != 1 ||
1308 !args->GetString(0, &service_path)) {
1309 NOTREACHED();
1310 return;
1311 }
1312 const chromeos::CellularNetwork* cellular =
1313 cros_->FindCellularNetworkByPath(service_path);
1314 if (cellular)
1315 cellular->RefreshDataPlansIfNeeded();
1316 }
1317
1318 ListValue* InternetOptionsHandler::GetWiredList() {
1319 ListValue* list = new ListValue();
1320
1321 // If ethernet is not enabled, then don't add anything.
1322 if (cros_->ethernet_enabled()) {
1323 const chromeos::EthernetNetwork* ethernet_network =
1324 cros_->ethernet_network();
1325 if (ethernet_network) {
1326 NetworkInfoDictionary network_dict(ethernet_network,
1327 web_ui()->GetDeviceScale());
1328 network_dict.set_name(
1329 l10n_util::GetStringUTF8(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET)),
1330 list->Append(network_dict.BuildDictionary());
1331 }
1332 }
1333 return list;
1334 }
1335
1336 ListValue* InternetOptionsHandler::GetWirelessList() {
1337 ListValue* list = new ListValue();
1338
1339 const chromeos::WifiNetworkVector& wifi_networks = cros_->wifi_networks();
1340 for (chromeos::WifiNetworkVector::const_iterator it =
1341 wifi_networks.begin(); it != wifi_networks.end(); ++it) {
1342 NetworkInfoDictionary network_dict(*it, web_ui()->GetDeviceScale());
1343 network_dict.set_connectable(cros_->CanConnectToNetwork(*it));
1344 list->Append(network_dict.BuildDictionary());
1345 }
1346
1347 const chromeos::WimaxNetworkVector& wimax_networks = cros_->wimax_networks();
1348 for (chromeos::WimaxNetworkVector::const_iterator it =
1349 wimax_networks.begin(); it != wimax_networks.end(); ++it) {
1350 NetworkInfoDictionary network_dict(*it, web_ui()->GetDeviceScale());
1351 network_dict.set_connectable(cros_->CanConnectToNetwork(*it));
1352 list->Append(network_dict.BuildDictionary());
1353 }
1354
1355 const chromeos::CellularNetworkVector cellular_networks =
1356 cros_->cellular_networks();
1357 for (chromeos::CellularNetworkVector::const_iterator it =
1358 cellular_networks.begin(); it != cellular_networks.end(); ++it) {
1359 NetworkInfoDictionary network_dict(*it, web_ui()->GetDeviceScale());
1360 network_dict.set_connectable(cros_->CanConnectToNetwork(*it));
1361 network_dict.set_activation_state((*it)->activation_state());
1362 network_dict.set_needs_new_plan(
1363 (*it)->SupportsDataPlan() && (*it)->restricted_pool());
1364 list->Append(network_dict.BuildDictionary());
1365 }
1366
1367 const chromeos::NetworkDevice* cellular_device = cros_->FindCellularDevice();
1368 if (cellular_device && cellular_device->support_network_scan() &&
1369 cros_->cellular_enabled()) {
1370 NetworkInfoDictionary network_dict(web_ui()->GetDeviceScale());
1371 network_dict.set_service_path(kOtherNetworksFakePath);
1372 network_dict.set_icon(
1373 chromeos::NetworkMenuIcon::GetDisconnectedImage(
1374 chromeos::NetworkMenuIcon::BARS,
1375 chromeos::NetworkMenuIcon::COLOR_DARK));
1376 network_dict.set_name(
1377 l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_OTHER_CELLULAR_NETWORKS));
1378 network_dict.set_connectable(true);
1379 network_dict.set_connection_type(chromeos::TYPE_CELLULAR);
1380 network_dict.set_activation_state(chromeos::ACTIVATION_STATE_ACTIVATED);
1381 list->Append(network_dict.BuildDictionary());
1382 }
1383
1384 return list;
1385 }
1386
1387 ListValue* InternetOptionsHandler::GetVPNList() {
1388 ListValue* list = new ListValue();
1389
1390 const chromeos::VirtualNetworkVector& virtual_networks =
1391 cros_->virtual_networks();
1392 for (chromeos::VirtualNetworkVector::const_iterator it =
1393 virtual_networks.begin(); it != virtual_networks.end(); ++it) {
1394 NetworkInfoDictionary network_dict(*it, web_ui()->GetDeviceScale());
1395 network_dict.set_connectable(cros_->CanConnectToNetwork(*it));
1396 list->Append(network_dict.BuildDictionary());
1397 }
1398
1399 return list;
1400 }
1401
1402 ListValue* InternetOptionsHandler::GetRememberedList() {
1403 ListValue* list = new ListValue();
1404
1405 for (chromeos::WifiNetworkVector::const_iterator rit =
1406 cros_->remembered_wifi_networks().begin();
1407 rit != cros_->remembered_wifi_networks().end(); ++rit) {
1408 chromeos::WifiNetwork* remembered = *rit;
1409 chromeos::WifiNetwork* wifi = static_cast<chromeos::WifiNetwork*>(
1410 cros_->FindNetworkByUniqueId(remembered->unique_id()));
1411
1412 NetworkInfoDictionary network_dict(wifi,
1413 remembered,
1414 web_ui()->GetDeviceScale());
1415 list->Append(network_dict.BuildDictionary());
1416 }
1417
1418 for (chromeos::VirtualNetworkVector::const_iterator rit =
1419 cros_->remembered_virtual_networks().begin();
1420 rit != cros_->remembered_virtual_networks().end(); ++rit) {
1421 chromeos::VirtualNetwork* remembered = *rit;
1422 chromeos::VirtualNetwork* vpn = static_cast<chromeos::VirtualNetwork*>(
1423 cros_->FindNetworkByUniqueId(remembered->unique_id()));
1424
1425 NetworkInfoDictionary network_dict(vpn,
1426 remembered,
1427 web_ui()->GetDeviceScale());
1428 list->Append(network_dict.BuildDictionary());
1429 }
1430
1431 return list;
1432 }
1433
1434 void InternetOptionsHandler::FillNetworkInfo(DictionaryValue* dictionary) {
1435 dictionary->SetBoolean("accessLocked", cros_->IsLocked());
1436 dictionary->Set("wiredList", GetWiredList());
1437 dictionary->Set("wirelessList", GetWirelessList());
1438 dictionary->Set("vpnList", GetVPNList());
1439 dictionary->Set("rememberedList", GetRememberedList());
1440 dictionary->SetBoolean("wifiAvailable", cros_->wifi_available());
1441 dictionary->SetBoolean("wifiBusy", cros_->wifi_busy());
1442 dictionary->SetBoolean("wifiEnabled", cros_->wifi_enabled());
1443 dictionary->SetBoolean("cellularAvailable", cros_->cellular_available());
1444 dictionary->SetBoolean("cellularBusy", cros_->cellular_busy());
1445 dictionary->SetBoolean("cellularEnabled", cros_->cellular_enabled());
1446 dictionary->SetBoolean("wimaxEnabled", cros_->wimax_enabled());
1447 dictionary->SetBoolean("wimaxAvailable", cros_->wimax_available());
1448 dictionary->SetBoolean("wimaxBusy", cros_->wimax_busy());
1449 // TODO(kevers): The use of 'offline_mode' is not quite correct. Update once
1450 // we have proper back-end support.
1451 dictionary->SetBoolean("airplaneMode", cros_->offline_mode());
1452 }
1453
1454 void InternetOptionsHandler::SetValueDictionary(
1455 DictionaryValue* settings,
1456 const char* key,
1457 base::Value* value,
1458 const chromeos::NetworkPropertyUIData& ui_data) {
1459 DictionaryValue* value_dict = new DictionaryValue();
1460 // DictionaryValue::Set() takes ownership of |value|.
1461 if (value)
1462 value_dict->Set("value", value);
1463 const base::Value* default_value = ui_data.default_value();
1464 if (default_value)
1465 value_dict->Set("default", default_value->DeepCopy());
1466 if (ui_data.managed())
1467 value_dict->SetString("controlledBy", "policy");
1468 else if (ui_data.recommended())
1469 value_dict->SetString("controlledBy", "recommended");
1470 settings->Set(key, value_dict);
1471 }
1472
1473 } // namespace options2
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698