• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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// require: onc_data.js
6
7// NOTE(stevenjb): This code is in the process of being converted to be
8// compatible with the networkingPrivate extension API:
9// * The network property dictionaries are being converted to use ONC values.
10// * chrome.send calls will be replaced with an API object that simulates the
11//   networkingPrivate API. See network_config.js.
12// See crbug.com/279351 for more info.
13
14/** @typedef {{address: (string|undefined),
15 *             gateway: (string|undefined),
16 *             nameServers: (string|undefined),
17 *             netmask: (string|undefined),
18 *             prefixLength: (number|undefined)}}
19 * @see chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
20 */
21var IPInfo;
22
23/**
24 * InternetDetailedInfo argument passed to showDetailedInfo.
25 * @see chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
26 * @typedef {{
27 *   servicePath: string,
28 *   showCarrierSelect: (boolean|undefined),
29 *   showViewAccountButton: (boolean|undefined)
30 * }}
31 */
32var InternetDetailedInfo;
33
34cr.define('options.internet', function() {
35  var OncData = cr.onc.OncData;
36  var Page = cr.ui.pageManager.Page;
37  var PageManager = cr.ui.pageManager.PageManager;
38  /** @const */ var IPAddressField = options.internet.IPAddressField;
39
40  /** @const */ var GoogleNameServersString = '8.8.4.4,8.8.8.8';
41  /** @const */ var CarrierGenericUMTS = 'Generic UMTS';
42
43  /**
44   * Helper function to set hidden attribute for elements matching a selector.
45   * @param {string} selector CSS selector for extracting a list of elements.
46   * @param {boolean} hidden New hidden value.
47   */
48  function updateHidden(selector, hidden) {
49    var elements = cr.doc.querySelectorAll(selector);
50    for (var i = 0, el; el = elements[i]; i++) {
51      el.hidden = hidden;
52    }
53  }
54
55  /**
56   * Helper function to update the properties of the data object from the
57   * properties in the update object.
58   * @param {Object} data Object to update.
59   * @param {Object} update Object containing the updated properties.
60   */
61  function updateDataObject(data, update) {
62    for (var prop in update) {
63      if (prop in data)
64        data[prop] = update[prop];
65    }
66  }
67
68  /**
69   * Monitor pref change of given element.
70   * @param {Element} el Target element.
71   */
72  function observePrefsUI(el) {
73    Preferences.getInstance().addEventListener(el.pref, handlePrefUpdate);
74  }
75
76  /**
77   * UI pref change handler.
78   * @param {Event} e The update event.
79   */
80  function handlePrefUpdate(e) {
81    DetailsInternetPage.getInstance().updateControls();
82  }
83
84  /**
85   * Simple helper method for converting a field to a string. It is used to
86   * easily assign an empty string from fields that may be unknown or undefined.
87   * @param {Object} value that should be converted to a string.
88   * @return {string} the result.
89   */
90  function stringFromValue(value) {
91    return value ? String(value) : '';
92  }
93
94  /**
95   * @param {string} action An action to send to coreOptionsUserMetricsAction.
96   */
97  function sendChromeMetricsAction(action) {
98    chrome.send('coreOptionsUserMetricsAction', [action]);
99  }
100
101  /**
102   * Sends the 'checked' state of a control to chrome for a network.
103   * @param {string} path The service path of the network.
104   * @param {string} message The message to send to chrome.
105   * @param {string} checkboxId The id of the checkbox with the value to send.
106   * @param {string=} opt_action Optional action to record.
107   */
108  function sendCheckedIfEnabled(path, message, checkboxId, opt_action) {
109    var checkbox = assertInstanceof($(checkboxId), HTMLInputElement);
110    if (!checkbox.hidden && !checkbox.disabled) {
111      chrome.send(message, [path, checkbox.checked ? 'true' : 'false']);
112      if (opt_action)
113        sendChromeMetricsAction(opt_action);
114    }
115  }
116
117  /**
118   * Send metrics to Chrome when the detailed page is opened.
119   * @param {string} type The ONC type of the network being shown.
120   * @param {string} state The ONC network state.
121   */
122  function sendShowDetailsMetrics(type, state) {
123    if (type == 'WiFi') {
124      sendChromeMetricsAction('Options_NetworkShowDetailsWifi');
125      if (state != 'NotConnected')
126        sendChromeMetricsAction('Options_NetworkShowDetailsWifiConnected');
127    } else if (type == 'Cellular') {
128      sendChromeMetricsAction('Options_NetworkShowDetailsCellular');
129      if (state != 'NotConnected')
130        sendChromeMetricsAction('Options_NetworkShowDetailsCellularConnected');
131    } else if (type == 'VPN') {
132      sendChromeMetricsAction('Options_NetworkShowDetailsVPN');
133      if (state != 'NotConnected')
134        sendChromeMetricsAction('Options_NetworkShowDetailsVPNConnected');
135    }
136  }
137
138  /**
139   * Returns the netmask as a string for a given prefix length.
140   * @param {number} prefixLength The ONC routing prefix length.
141   * @return {string} The corresponding netmask.
142   */
143  function prefixLengthToNetmask(prefixLength) {
144    // Return the empty string for invalid inputs.
145    if (prefixLength < 0 || prefixLength > 32)
146      return '';
147    var netmask = '';
148    for (var i = 0; i < 4; ++i) {
149      var remainder = 8;
150      if (prefixLength >= 8) {
151        prefixLength -= 8;
152      } else {
153        remainder = prefixLength;
154        prefixLength = 0;
155      }
156      if (i > 0)
157        netmask += '.';
158      var value = 0;
159      if (remainder != 0)
160        value = ((2 << (remainder - 1)) - 1) << (8 - remainder);
161      netmask += value.toString();
162    }
163    return netmask;
164  }
165
166  /////////////////////////////////////////////////////////////////////////////
167  // DetailsInternetPage class:
168
169  /**
170   * Encapsulated handling of ChromeOS internet details overlay page.
171   * @constructor
172   * @extends {cr.ui.pageManager.Page}
173   */
174  function DetailsInternetPage() {
175    // Cached Apn properties
176    this.userApnIndex_ = -1;
177    this.selectedApnIndex_ = -1;
178    this.userApn_ = {};
179    // We show the Proxy configuration tab for remembered networks and when
180    // configuring a proxy from the login screen.
181    this.showProxy_ = false;
182    // In Chrome we sometimes want to enable the Cellular carrier select UI.
183    this.showCarrierSelect_ = false;
184    // In Chrome we sometimes want to show the 'View Account' button.
185    this.showViewAccountButton_ = false;
186
187    Page.call(this, 'detailsInternetPage', '', 'details-internet-page');
188  }
189
190  cr.addSingletonGetter(DetailsInternetPage);
191
192  DetailsInternetPage.prototype = {
193    __proto__: Page.prototype,
194
195    /** @override */
196    initializePage: function() {
197      Page.prototype.initializePage.call(this);
198      this.initializePageContents_();
199      this.showNetworkDetails_();
200    },
201
202    /**
203     * Auto-activates the network details dialog if network information
204     * is included in the URL.
205     */
206    showNetworkDetails_: function() {
207      var servicePath = parseQueryParams(window.location).servicePath;
208      if (!servicePath || !servicePath.length)
209        return;
210      var networkType = '';  // ignored for 'showDetails'
211      chrome.send('networkCommand', [networkType, servicePath, 'showDetails']);
212    },
213
214    /**
215     * Initializes the contents of the page.
216     */
217    initializePageContents_: function() {
218      $('details-internet-dismiss').addEventListener('click', function(event) {
219        DetailsInternetPage.setDetails();
220      });
221
222      $('details-internet-login').addEventListener('click', function(event) {
223        DetailsInternetPage.setDetails();
224        DetailsInternetPage.loginFromDetails();
225      });
226
227      $('details-internet-disconnect').addEventListener('click',
228                                                        function(event) {
229        DetailsInternetPage.setDetails();
230        DetailsInternetPage.disconnectNetwork();
231      });
232
233      $('details-internet-configure').addEventListener('click',
234                                                       function(event) {
235        DetailsInternetPage.setDetails();
236        DetailsInternetPage.configureNetwork();
237      });
238
239      $('activate-details').addEventListener('click', function(event) {
240        DetailsInternetPage.activateFromDetails();
241      });
242
243      $('view-account-details').addEventListener('click', function(event) {
244        chrome.send('showMorePlanInfo',
245                    [DetailsInternetPage.getInstance().servicePath_]);
246        PageManager.closeOverlay();
247      });
248
249      $('cellular-apn-use-default').addEventListener('click', function(event) {
250        DetailsInternetPage.getInstance().setDefaultApn_();
251      });
252
253      $('cellular-apn-set').addEventListener('click', function(event) {
254        DetailsInternetPage.getInstance().setApn_($('cellular-apn').value);
255      });
256
257      $('cellular-apn-cancel').addEventListener('click', function(event) {
258        DetailsInternetPage.getInstance().cancelApn_();
259      });
260
261      $('select-apn').addEventListener('change', function(event) {
262        DetailsInternetPage.getInstance().selectApn_();
263      });
264
265      $('sim-card-lock-enabled').addEventListener('click', function(event) {
266        var newValue = $('sim-card-lock-enabled').checked;
267        // Leave value as is because user needs to enter PIN code first.
268        // When PIN will be entered and value changed,
269        // we'll update UI to reflect that change.
270        $('sim-card-lock-enabled').checked = !newValue;
271        var operation = newValue ? 'setLocked' : 'setUnlocked';
272        chrome.send('simOperation', [operation]);
273      });
274      $('change-pin').addEventListener('click', function(event) {
275        chrome.send('simOperation', ['changePin']);
276      });
277
278      // Proxy
279      ['proxy-host-single-port',
280       'secure-proxy-port',
281       'socks-port',
282       'ftp-proxy-port',
283       'proxy-host-port'
284      ].forEach(function(id) {
285        options.PrefPortNumber.decorate($(id));
286      });
287
288      options.proxyexceptions.ProxyExceptions.decorate($('ignored-host-list'));
289      $('remove-host').addEventListener('click',
290                                        this.handleRemoveProxyExceptions_);
291      $('add-host').addEventListener('click', this.handleAddProxyException_);
292      $('direct-proxy').addEventListener('click', this.disableManualProxy_);
293      $('manual-proxy').addEventListener('click', this.enableManualProxy_);
294      $('auto-proxy').addEventListener('click', this.disableManualProxy_);
295      $('proxy-all-protocols').addEventListener('click',
296                                                this.toggleSingleProxy_);
297      $('proxy-use-pac-url').addEventListener('change',
298                                              this.handleAutoConfigProxy_);
299
300      observePrefsUI($('direct-proxy'));
301      observePrefsUI($('manual-proxy'));
302      observePrefsUI($('auto-proxy'));
303      observePrefsUI($('proxy-all-protocols'));
304      observePrefsUI($('proxy-use-pac-url'));
305
306      $('ip-automatic-configuration-checkbox').addEventListener('click',
307        this.handleIpAutoConfig_);
308      $('automatic-dns-radio').addEventListener('click',
309        this.handleNameServerTypeChange_);
310      $('google-dns-radio').addEventListener('click',
311        this.handleNameServerTypeChange_);
312      $('user-dns-radio').addEventListener('click',
313        this.handleNameServerTypeChange_);
314
315      // We only load this string if we have the string data available
316      // because the proxy settings page on the login screen re-uses the
317      // proxy sub-page from the internet options, and it doesn't ever
318      // show the DNS settings, so we don't need this string there.
319      // The string isn't available because
320      // chrome://settings-frame/strings.js (where the string is
321      // stored) is not accessible from the login screen.
322      // TODO(pneubeck): Remove this once i18n of the proxy dialog on the login
323      // page is fixed. http://crbug.com/242865
324      if (loadTimeData.data_) {
325        $('google-dns-label').innerHTML =
326            loadTimeData.getString('googleNameServers');
327      }
328    },
329
330    /**
331     * Handler for "add" event fired from userNameEdit.
332     * @param {Event} e Add event fired from userNameEdit.
333     * @private
334     */
335    handleAddProxyException_: function(e) {
336      var exception = $('new-host').value;
337      $('new-host').value = '';
338
339      exception = exception.trim();
340      if (exception)
341        $('ignored-host-list').addException(exception);
342    },
343
344    /**
345     * Handler for when the remove button is clicked
346     * @param {Event} e The click event.
347     * @private
348     */
349    handleRemoveProxyExceptions_: function(e) {
350      var selectedItems = $('ignored-host-list').selectedItems;
351      for (var x = 0; x < selectedItems.length; x++) {
352        $('ignored-host-list').removeException(selectedItems[x]);
353      }
354    },
355
356    /**
357     * Handler for when the IP automatic configuration checkbox is clicked.
358     * @param {Event} e The click event.
359     * @private
360     */
361    handleIpAutoConfig_: function(e) {
362      var checked = $('ip-automatic-configuration-checkbox').checked;
363      var fields = [$('ip-address'), $('ip-netmask'), $('ip-gateway')];
364      for (var i = 0; i < fields.length; ++i) {
365        fields[i].editable = !checked;
366        if (checked) {
367          var model = fields[i].model;
368          model.value = model.automatic;
369          fields[i].model = model;
370        }
371      }
372      if (!checked)
373        $('ip-address').focus();
374    },
375
376    /**
377     * Handler for when the name server selection changes.
378     * @param {Event} event The click event.
379     * @private
380     */
381    handleNameServerTypeChange_: function(event) {
382      var type = event.target.value;
383      DetailsInternetPage.updateNameServerDisplay(type);
384    },
385
386    /**
387     * Sends the IP Config info to chrome.
388     * @param {string} nameServerType The selected name server type:
389     *   'automatic', 'google', or 'user'.
390     * @private
391     */
392    sendIpConfig_: function(nameServerType) {
393      var userNameServerString = '';
394      if (nameServerType == 'user') {
395        var userNameServers = [];
396        for (var i = 1; i <= 4; ++i) {
397          var nameServerField = $('ipconfig-dns' + i);
398          // Skip empty values.
399          if (nameServerField && nameServerField.model &&
400              nameServerField.model.value) {
401            userNameServers.push(nameServerField.model.value);
402          }
403        }
404        userNameServerString = userNameServers.sort().join(',');
405      }
406      chrome.send('setIPConfig',
407                  [this.servicePath_,
408                   Boolean($('ip-automatic-configuration-checkbox').checked),
409                   $('ip-address').model.value || '',
410                   $('ip-netmask').model.value || '',
411                   $('ip-gateway').model.value || '',
412                   nameServerType,
413                   userNameServerString]);
414    },
415
416    /**
417     * Creates an indicator event for controlled properties using
418     * the same dictionary format as CoreOptionsHandler::CreateValueForPref.
419     * @param {string} name The name for the Event.
420     * @param {{value: *, controlledBy: *, recommendedValue: *}} propData
421     *     Property dictionary.
422     * @private
423     */
424    createControlledEvent_: function(name, propData) {
425      assert('value' in propData && 'controlledBy' in propData &&
426             'recommendedValue' in propData);
427      var event = new Event(name);
428      event.value = {
429        value: propData.value,
430        controlledBy: propData.controlledBy,
431        recommendedValue: propData.recommendedValue
432      };
433      return event;
434    },
435
436    /**
437     * Creates an indicator event for controlled properties using
438     * the ONC getManagedProperties dictionary format.
439     * @param {string} name The name for the Event.
440     * @param {Object} propData ONC managed network property dictionary.
441     * @private
442     */
443    createManagedEvent_: function(name, propData) {
444      var event = new Event(name);
445      event.value = {};
446
447      // Set the current value and recommended value.
448      var activeValue = propData['Active'];
449      var effective = propData['Effective'];
450      if (activeValue == undefined)
451        activeValue = propData[effective];
452      event.value.value = activeValue;
453
454      // If a property is editable then it is not enforced, and 'controlledBy'
455      // is set to 'recommended' unless effective == {User|Shared}Setting, in
456      // which case the value was modified from the recommended value.
457      // Otherwise if 'Effective' is set to 'UserPolicy' or 'DevicePolicy' then
458      // the set value is mandated by the policy.
459      if (propData['UserEditable']) {
460        if (effective == 'UserPolicy')
461          event.value.controlledBy = 'recommended';
462        event.value.recommendedValue = propData['UserPolicy'];
463      } else if (propData['DeviceEditable']) {
464        if (effective == 'DevicePolicy')
465          event.value.controlledBy = 'recommended';
466        event.value.recommendedValue = propData['DevicePolicy'];
467      } else if (effective == 'UserPolicy' || effective == 'DevicePolicy') {
468        event.value.controlledBy = 'policy';
469      }
470
471      return event;
472    },
473
474    /**
475     * Update details page controls.
476     */
477    updateControls: function() {
478      // Note: onc may be undefined when called from a pref update before
479      // initialized in sendNetworkDetails.
480      var onc = this.onc_;
481
482      // Always show the ipconfig section. TODO(stevenjb): Improve the display
483      // for unconnected networks. Currently the IP address fields may be
484      // blank if the network is not connected.
485      $('ipconfig-section').hidden = false;
486      $('ipconfig-dns-section').hidden = false;
487
488      // Network type related.
489      updateHidden('#details-internet-page .cellular-details',
490                   this.type_ != 'Cellular');
491      updateHidden('#details-internet-page .wifi-details',
492                   this.type_ != 'WiFi');
493      updateHidden('#details-internet-page .wimax-details',
494                   this.type_ != 'WiMAX');
495      updateHidden('#details-internet-page .vpn-details', this.type_ != 'VPN');
496      updateHidden('#details-internet-page .proxy-details', !this.showProxy_);
497
498      // Cellular
499      if (onc && this.type_ == 'Cellular') {
500        // Hide gsm/cdma specific elements.
501        if (onc.getActiveValue('Cellular.Family') == 'GSM')
502          updateHidden('#details-internet-page .cdma-only', true);
503        else
504          updateHidden('#details-internet-page .gsm-only', true);
505      }
506
507      // Wifi
508
509      // Hide network tab for VPN.
510      updateHidden('#details-internet-page .network-details',
511                   this.type_ == 'VPN');
512
513      // Password and shared.
514      var source = onc ? onc.getSource() : 'None';
515      var shared = (source == 'Device' || source == 'DevicePolicy');
516      var security = onc ? onc.getWiFiSecurity() : 'None';
517      updateHidden('#details-internet-page #password-details',
518                   this.type_ != 'WiFi' || security == 'None');
519      updateHidden('#details-internet-page #wifi-shared-network', !shared);
520      updateHidden('#details-internet-page #prefer-network', source == 'None');
521
522      // WiMAX.
523      updateHidden('#details-internet-page #wimax-shared-network', !shared);
524
525      // Proxy
526      this.updateProxyBannerVisibility_();
527      this.toggleSingleProxy_();
528      if ($('manual-proxy').checked)
529        this.enableManualProxy_();
530      else
531        this.disableManualProxy_();
532    },
533
534    /**
535     * Updates info banner visibility state. This function shows the banner
536     * if proxy is managed or shared-proxies is off for shared network.
537     * @private
538     */
539    updateProxyBannerVisibility_: function() {
540      var bannerDiv = $('network-proxy-info-banner');
541      if (!loadTimeData.data_) {
542        // TODO(pneubeck): This temporarily prevents an exception below until
543        // i18n of the proxy dialog on the login page is
544        // fixed. http://crbug.com/242865
545        bannerDiv.hidden = true;
546        return;
547      }
548
549      // Show banner and determine its message if necessary.
550      var controlledBy = $('direct-proxy').controlledBy;
551      if (!controlledBy || controlledBy == '') {
552        bannerDiv.hidden = true;
553      } else {
554        bannerDiv.hidden = false;
555        // The possible banner texts are loaded in proxy_handler.cc.
556        var bannerText = 'proxyBanner' + controlledBy.charAt(0).toUpperCase() +
557                         controlledBy.slice(1);
558        $('banner-text').textContent = loadTimeData.getString(bannerText);
559      }
560    },
561
562    /**
563     * Handler for when the user clicks on the checkbox to allow a
564     * single proxy usage.
565     * @private
566     */
567    toggleSingleProxy_: function() {
568      if ($('proxy-all-protocols').checked) {
569        $('multi-proxy').hidden = true;
570        $('single-proxy').hidden = false;
571      } else {
572        $('multi-proxy').hidden = false;
573        $('single-proxy').hidden = true;
574      }
575    },
576
577    /**
578     * Handler for when the user clicks on the checkbox to enter
579     * auto configuration URL.
580     * @private
581     */
582    handleAutoConfigProxy_: function() {
583      $('proxy-pac-url').disabled = !$('proxy-use-pac-url').checked;
584    },
585
586    /**
587     * Handler for selecting a radio button that will disable the manual
588     * controls.
589     * @private
590     */
591    disableManualProxy_: function() {
592      $('ignored-host-list').disabled = true;
593      $('new-host').disabled = true;
594      $('remove-host').disabled = true;
595      $('add-host').disabled = true;
596      $('proxy-all-protocols').disabled = true;
597      $('proxy-host-name').disabled = true;
598      $('proxy-host-port').disabled = true;
599      $('proxy-host-single-name').disabled = true;
600      $('proxy-host-single-port').disabled = true;
601      $('secure-proxy-host-name').disabled = true;
602      $('secure-proxy-port').disabled = true;
603      $('ftp-proxy').disabled = true;
604      $('ftp-proxy-port').disabled = true;
605      $('socks-host').disabled = true;
606      $('socks-port').disabled = true;
607      $('proxy-use-pac-url').disabled = $('auto-proxy').disabled ||
608                                        !$('auto-proxy').checked;
609      $('proxy-pac-url').disabled = $('proxy-use-pac-url').disabled ||
610                                    !$('proxy-use-pac-url').checked;
611      $('auto-proxy-parms').hidden = !$('auto-proxy').checked;
612      $('manual-proxy-parms').hidden = !$('manual-proxy').checked;
613      sendChromeMetricsAction('Options_NetworkManualProxy_Disable');
614    },
615
616    /**
617     * Handler for selecting a radio button that will enable the manual
618     * controls.
619     * @private
620     */
621    enableManualProxy_: function() {
622      $('ignored-host-list').redraw();
623      var allDisabled = $('manual-proxy').disabled;
624      $('ignored-host-list').disabled = allDisabled;
625      $('new-host').disabled = allDisabled;
626      $('remove-host').disabled = allDisabled;
627      $('add-host').disabled = allDisabled;
628      $('proxy-all-protocols').disabled = allDisabled;
629      $('proxy-host-name').disabled = allDisabled;
630      $('proxy-host-port').disabled = allDisabled;
631      $('proxy-host-single-name').disabled = allDisabled;
632      $('proxy-host-single-port').disabled = allDisabled;
633      $('secure-proxy-host-name').disabled = allDisabled;
634      $('secure-proxy-port').disabled = allDisabled;
635      $('ftp-proxy').disabled = allDisabled;
636      $('ftp-proxy-port').disabled = allDisabled;
637      $('socks-host').disabled = allDisabled;
638      $('socks-port').disabled = allDisabled;
639      $('proxy-use-pac-url').disabled = true;
640      $('proxy-pac-url').disabled = true;
641      $('auto-proxy-parms').hidden = !$('auto-proxy').checked;
642      $('manual-proxy-parms').hidden = !$('manual-proxy').checked;
643      sendChromeMetricsAction('Options_NetworkManualProxy_Enable');
644    },
645
646    /**
647     * Helper method called from showDetailedInfo and updateConnectionData.
648     * Updates visibility/enabled of the login/disconnect/configure buttons.
649     * @private
650     */
651    updateConnectionButtonVisibilty_: function() {
652      var onc = this.onc_;
653      if (this.type_ == 'Ethernet') {
654        // Ethernet can never be connected or disconnected and can always be
655        // configured (e.g. to set security).
656        $('details-internet-login').hidden = true;
657        $('details-internet-disconnect').hidden = true;
658        $('details-internet-configure').hidden = false;
659        return;
660      }
661
662      var connectState = onc.getActiveValue('ConnectionState');
663      if (connectState == 'NotConnected') {
664        $('details-internet-login').hidden = false;
665        // Connecting to an unconfigured network might trigger certificate
666        // installation UI. Until that gets handled here, always enable the
667        // Connect button.
668        $('details-internet-login').disabled = false;
669        $('details-internet-disconnect').hidden = true;
670      } else {
671        $('details-internet-login').hidden = true;
672        $('details-internet-disconnect').hidden = false;
673      }
674
675      var connectable = onc.getActiveValue('Connectable');
676      if (connectState != 'Connected' &&
677          (!connectable || onc.getWiFiSecurity() != 'None' ||
678          (this.type_ == 'WiMAX' || this.type_ == 'VPN'))) {
679        $('details-internet-configure').hidden = false;
680      } else {
681        $('details-internet-configure').hidden = true;
682      }
683    },
684
685    /**
686     * Helper method called from showDetailedInfo and updateConnectionData.
687     * Updates the connection state property and account / sim card links.
688     * @private
689     */
690    updateDetails_: function() {
691      var onc = this.onc_;
692
693      var connectionStateString = onc.getTranslatedValue('ConnectionState');
694      $('connection-state').textContent = connectionStateString;
695
696      var type = this.type_;
697      var showViewAccount = false;
698      var showActivate = false;
699      if (type == 'WiFi') {
700        $('wifi-connection-state').textContent = connectionStateString;
701      } else if (type == 'WiMAX') {
702        $('wimax-connection-state').textContent = connectionStateString;
703      } else if (type == 'Cellular') {
704        $('activation-state').textContent =
705            onc.getTranslatedValue('Cellular.ActivationState');
706        if (onc.getActiveValue('Cellular.Family') == 'GSM') {
707          var lockEnabled =
708              onc.getActiveValue('Cellular.SIMLockStatus.LockEnabled');
709          $('sim-card-lock-enabled').checked = lockEnabled;
710          $('change-pin').hidden = !lockEnabled;
711        }
712        showViewAccount = this.showViewAccountButton_;
713        var activationState = onc.getActiveValue('Cellular.ActivationState');
714        showActivate = activationState == 'NotActivated' ||
715            activationState == 'PartiallyActivated';
716      }
717
718      $('view-account-details').hidden = !showViewAccount;
719      $('activate-details').hidden = !showActivate;
720      // If activation is not complete, hide the login button.
721      if (showActivate)
722        $('details-internet-login').hidden = true;
723    },
724
725    /**
726     * Helper method called from showDetailedInfo and updateConnectionData.
727     * Updates the fields in the header section of the details frame.
728     * @private
729     */
730    populateHeader_: function() {
731      var onc = this.onc_;
732
733      $('network-details-title').textContent = onc.getTranslatedValue('Name');
734      var connectionState = onc.getActiveValue('ConnectionState');
735      var connectionStateString = onc.getTranslatedValue('ConnectionState');
736      $('network-details-subtitle-status').textContent = connectionStateString;
737
738      var typeKey;
739      var type = this.type_;
740      if (type == 'Ethernet')
741        typeKey = 'ethernetTitle';
742      else if (type == 'WiFi')
743        typeKey = 'wifiTitle';
744      else if (type == 'WiMAX')
745        typeKey = 'wimaxTitle';
746      else if (type == 'Cellular')
747        typeKey = 'cellularTitle';
748      else if (type == 'VPN')
749        typeKey = 'vpnTitle';
750      else
751        typeKey = null;
752      var typeLabel = $('network-details-subtitle-type');
753      var typeSeparator = $('network-details-subtitle-separator');
754      if (typeKey) {
755        typeLabel.textContent = loadTimeData.getString(typeKey);
756        typeLabel.hidden = false;
757        typeSeparator.hidden = false;
758      } else {
759        typeLabel.hidden = true;
760        typeSeparator.hidden = true;
761      }
762    },
763
764    /**
765     * Helper method called from showDetailedInfo to initialize the Apn list.
766     * @private
767     */
768    initializeApnList_: function() {
769      var onc = this.onc_;
770
771      var apnSelector = $('select-apn');
772      // Clear APN lists, keep only last element that "other".
773      while (apnSelector.length != 1) {
774        apnSelector.remove(0);
775      }
776      var otherOption = apnSelector[0];
777      var activeApn = onc.getActiveValue('Cellular.APN.AccessPointName');
778      var activeUsername = onc.getActiveValue('Cellular.APN.Username');
779      var activePassword = onc.getActiveValue('Cellular.APN.Password');
780      var lastGoodApn =
781          onc.getActiveValue('Cellular.LastGoodAPN.AccessPointName');
782      var lastGoodUsername =
783          onc.getActiveValue('Cellular.LastGoodAPN.Username');
784      var lastGoodPassword =
785          onc.getActiveValue('Cellular.LastGoodAPN.Password');
786      var apnList = onc.getActiveValue('Cellular.APNList');
787      for (var i = 0; i < apnList.length; i++) {
788        var apnDict = apnList[i];
789        var option = document.createElement('option');
790        var localizedName = apnDict['LocalizedName'];
791        var name = localizedName ? localizedName : apnDict['Name'];
792        var accessPointName = apnDict['AccessPointName'];
793        option.textContent =
794            name ? (name + ' (' + accessPointName + ')') : accessPointName;
795        option.value = i;
796        // Insert new option before "other" option.
797        apnSelector.add(option, otherOption);
798        if (this.selectedApnIndex_ != -1)
799          continue;
800        // If this matches the active Apn, or LastGoodApn (or there is no last
801        // good APN), set it as the selected Apn.
802        if ((activeApn == accessPointName &&
803             activeUsername == apnDict['Username'] &&
804             activePassword == apnDict['Password']) ||
805            (!activeApn && !lastGoodApn) ||
806            (!activeApn &&
807             lastGoodApn == accessPointName &&
808             lastGoodUsername == apnDict['Username'] &&
809             lastGoodPassword == apnDict['Password'])) {
810          this.selectedApnIndex_ = i;
811        }
812      }
813      if (this.selectedApnIndex_ == -1 && activeApn) {
814        var activeOption = document.createElement('option');
815        activeOption.textContent = activeApn;
816        activeOption.value = -1;
817        apnSelector.add(activeOption, otherOption);
818        this.selectedApnIndex_ = apnSelector.length - 2;
819        this.userApnIndex_ = this.selectedApnIndex_;
820      }
821      assert(this.selectedApnIndex_ >= 0);
822      apnSelector.selectedIndex = this.selectedApnIndex_;
823      updateHidden('.apn-list-view', false);
824      updateHidden('.apn-details-view', true);
825    },
826
827    /**
828     * Event Listener for the cellular-apn-use-default button.
829     * @private
830     */
831    setDefaultApn_: function() {
832      var onc = this.onc_;
833      var apnSelector = $('select-apn');
834
835      if (this.userApnIndex_ != -1) {
836        apnSelector.remove(this.userApnIndex_);
837        this.userApnIndex_ = -1;
838      }
839
840      var iApn = -1;
841      var apnList = onc.getActiveValue('Cellular.APNList');
842      if (apnList != undefined && apnList.length > 0) {
843        iApn = 0;
844        var defaultApn = apnList[iApn];
845        var activeApn = {};
846        activeApn['AccessPointName'] =
847            stringFromValue(defaultApn['AccessPointName']);
848        activeApn['Username'] = stringFromValue(defaultApn['Username']);
849        activeApn['Password'] = stringFromValue(defaultApn['Password']);
850        onc.setManagedProperty('Cellular.APN', activeApn);
851        chrome.send('setApn', [this.servicePath_,
852                               activeApn['AccessPointName'],
853                               activeApn['Username'],
854                               activeApn['Password']]);
855      }
856      apnSelector.selectedIndex = iApn;
857      this.selectedApnIndex_ = iApn;
858
859      updateHidden('.apn-list-view', false);
860      updateHidden('.apn-details-view', true);
861    },
862
863    /**
864     * Event Listener for the cellular-apn-set button.
865     * @private
866     */
867    setApn_: function(apnValue) {
868      if (apnValue == '')
869        return;
870
871      var onc = this.onc_;
872      var apnSelector = $('select-apn');
873
874      var activeApn = {};
875      activeApn['AccessPointName'] = stringFromValue(apnValue);
876      activeApn['Username'] = stringFromValue($('cellular-apn-username').value);
877      activeApn['Password'] = stringFromValue($('cellular-apn-password').value);
878      onc.setManagedProperty('Cellular.APN', activeApn);
879      this.userApn_ = activeApn;
880      chrome.send('setApn', [this.servicePath_,
881                             activeApn['AccessPointName'],
882                             activeApn['Username'],
883                             activeApn['Password']]);
884
885      if (this.userApnIndex_ != -1) {
886        apnSelector.remove(this.userApnIndex_);
887        this.userApnIndex_ = -1;
888      }
889
890      var option = document.createElement('option');
891      option.textContent = activeApn['AccessPointName'];
892      option.value = -1;
893      option.selected = true;
894      apnSelector.add(option, apnSelector[apnSelector.length - 1]);
895      this.userApnIndex_ = apnSelector.length - 2;
896      this.selectedApnIndex_ = this.userApnIndex_;
897
898      updateHidden('.apn-list-view', false);
899      updateHidden('.apn-details-view', true);
900    },
901
902    /**
903     * Event Listener for the cellular-apn-cancel button.
904     * @private
905     */
906    cancelApn_: function() {
907      $('select-apn').selectedIndex = this.selectedApnIndex_;
908      updateHidden('.apn-list-view', false);
909      updateHidden('.apn-details-view', true);
910    },
911
912    /**
913     * Event Listener for the select-apn button.
914     * @private
915     */
916    selectApn_: function() {
917      var onc = this.onc_;
918      var apnSelector = $('select-apn');
919      var apnDict;
920      if (apnSelector[apnSelector.selectedIndex].value != -1) {
921        var apnList = onc.getActiveValue('Cellular.APNList');
922        var apnIndex = apnSelector.selectedIndex;
923        assert(apnIndex < apnList.length);
924        apnDict = apnList[apnIndex];
925        chrome.send('setApn', [this.servicePath_,
926                               stringFromValue(apnDict['AccessPointName']),
927                               stringFromValue(apnDict['Username']),
928                               stringFromValue(apnDict['Password'])]);
929        this.selectedApnIndex_ = apnIndex;
930      } else if (apnSelector.selectedIndex == this.userApnIndex_) {
931        apnDict = this.userApn_;
932        chrome.send('setApn', [this.servicePath_,
933                               stringFromValue(apnDict['AccessPointName']),
934                               stringFromValue(apnDict['Username']),
935                               stringFromValue(apnDict['Password'])]);
936        this.selectedApnIndex_ = apnSelector.selectedIndex;
937      } else {
938        $('cellular-apn').value =
939            stringFromValue(onc.getActiveValue('Cellular.APN.AccessPointName'));
940        $('cellular-apn-username').value =
941            stringFromValue(onc.getActiveValue('Cellular.APN.Username'));
942        $('cellular-apn-password').value =
943            stringFromValue(onc.getActiveValue('Cellular.APN.Password'));
944        updateHidden('.apn-list-view', true);
945        updateHidden('.apn-details-view', false);
946      }
947    }
948  };
949
950  /**
951   * Enables or Disables all buttons that provide operations on the cellular
952   * network.
953   */
954  DetailsInternetPage.changeCellularButtonsState = function(disable) {
955    var buttonsToDisableList =
956        new Array('details-internet-login',
957                  'details-internet-disconnect',
958                  'details-internet-configure',
959                  'activate-details',
960                  'view-account-details');
961
962    for (var i = 0; i < buttonsToDisableList.length; ++i) {
963      var button = $(buttonsToDisableList[i]);
964      button.disabled = disable;
965    }
966  };
967
968  /**
969   * Shows a spinner while the carrier is changed.
970   */
971  DetailsInternetPage.showCarrierChangeSpinner = function(visible) {
972    $('switch-carrier-spinner').hidden = !visible;
973    // Disable any buttons that allow us to operate on cellular networks.
974    DetailsInternetPage.changeCellularButtonsState(visible);
975  };
976
977  /**
978   * Changes the network carrier.
979   */
980  DetailsInternetPage.handleCarrierChanged = function() {
981    var carrierSelector = $('select-carrier');
982    var carrier = carrierSelector[carrierSelector.selectedIndex].textContent;
983    DetailsInternetPage.showCarrierChangeSpinner(true);
984    chrome.send('setCarrier', [
985      DetailsInternetPage.getInstance().servicePath_, carrier]);
986  };
987
988  /**
989   * Performs minimal initialization of the InternetDetails dialog in
990   * preparation for showing proxy-settings.
991   */
992  DetailsInternetPage.initializeProxySettings = function() {
993    DetailsInternetPage.getInstance().initializePageContents_();
994  };
995
996  /**
997   * Displays the InternetDetails dialog with only the proxy settings visible.
998   */
999  DetailsInternetPage.showProxySettings = function() {
1000    var detailsPage = DetailsInternetPage.getInstance();
1001    $('network-details-header').hidden = true;
1002    $('activate-details').hidden = true;
1003    $('view-account-details').hidden = true;
1004    $('web-proxy-auto-discovery').hidden = true;
1005    detailsPage.showProxy_ = true;
1006    updateHidden('#internet-tab', true);
1007    updateHidden('#details-tab-strip', true);
1008    updateHidden('#details-internet-page .action-area', true);
1009    detailsPage.updateControls();
1010    detailsPage.visible = true;
1011    sendChromeMetricsAction('Options_NetworkShowProxyTab');
1012  };
1013
1014  /**
1015   * Initializes even handling for keyboard driven flow.
1016   */
1017  DetailsInternetPage.initializeKeyboardFlow = function() {
1018    keyboard.initializeKeyboardFlow();
1019  };
1020
1021  DetailsInternetPage.updateProxySettings = function(type) {
1022      var proxyHost = null,
1023          proxyPort = null;
1024
1025      if (type == 'cros.session.proxy.singlehttp') {
1026        proxyHost = 'proxy-host-single-name';
1027        proxyPort = 'proxy-host-single-port';
1028      } else if (type == 'cros.session.proxy.httpurl') {
1029        proxyHost = 'proxy-host-name';
1030        proxyPort = 'proxy-host-port';
1031      } else if (type == 'cros.session.proxy.httpsurl') {
1032        proxyHost = 'secure-proxy-host-name';
1033        proxyPort = 'secure-proxy-port';
1034      } else if (type == 'cros.session.proxy.ftpurl') {
1035        proxyHost = 'ftp-proxy';
1036        proxyPort = 'ftp-proxy-port';
1037      } else if (type == 'cros.session.proxy.socks') {
1038        proxyHost = 'socks-host';
1039        proxyPort = 'socks-port';
1040      } else {
1041        return;
1042      }
1043
1044      var hostValue = $(proxyHost).value;
1045      if (hostValue.indexOf(':') !== -1) {
1046        if (hostValue.match(/:/g).length == 1) {
1047          hostValue = hostValue.split(':');
1048          $(proxyHost).value = hostValue[0];
1049          $(proxyPort).value = hostValue[1];
1050        }
1051      }
1052  };
1053
1054  DetailsInternetPage.updateCarrier = function() {
1055    DetailsInternetPage.showCarrierChangeSpinner(false);
1056  };
1057
1058  DetailsInternetPage.loginFromDetails = function() {
1059    var detailsPage = DetailsInternetPage.getInstance();
1060    if (detailsPage.type_ == 'WiFi')
1061      sendChromeMetricsAction('Options_NetworkConnectToWifi');
1062    else if (detailsPage.type_ == 'VPN')
1063      sendChromeMetricsAction('Options_NetworkConnectToVPN');
1064    // TODO(stevenjb): chrome.networkingPrivate.disableNetworkType
1065    chrome.send('startConnect', [detailsPage.servicePath_]);
1066    PageManager.closeOverlay();
1067  };
1068
1069  DetailsInternetPage.disconnectNetwork = function() {
1070    var detailsPage = DetailsInternetPage.getInstance();
1071    if (detailsPage.type_ == 'WiFi')
1072      sendChromeMetricsAction('Options_NetworkDisconnectWifi');
1073    else if (detailsPage.type_ == 'VPN')
1074      sendChromeMetricsAction('Options_NetworkDisconnectVPN');
1075    // TODO(stevenjb): chrome.networkingPrivate.startDisconnect
1076    chrome.send('startDisconnect', [detailsPage.servicePath_]);
1077    PageManager.closeOverlay();
1078  };
1079
1080  DetailsInternetPage.configureNetwork = function() {
1081    var detailsPage = DetailsInternetPage.getInstance();
1082    chrome.send('networkCommand',
1083                [detailsPage.type_, detailsPage.servicePath_, 'configure']);
1084    PageManager.closeOverlay();
1085  };
1086
1087  DetailsInternetPage.activateFromDetails = function() {
1088    var detailsPage = DetailsInternetPage.getInstance();
1089    if (detailsPage.type_ == 'Cellular') {
1090      chrome.send('networkCommand',
1091                  [detailsPage.type_, detailsPage.servicePath_, 'activate']);
1092    }
1093    PageManager.closeOverlay();
1094  };
1095
1096  /**
1097   * Event handler called when the details page is closed. Sends changed
1098   * properties to Chrome and closes the overlay.
1099   */
1100  DetailsInternetPage.setDetails = function() {
1101    var detailsPage = DetailsInternetPage.getInstance();
1102    var type = detailsPage.type_;
1103    var servicePath = detailsPage.servicePath_;
1104    if (type == 'WiFi') {
1105      sendCheckedIfEnabled(servicePath,
1106                           'setPreferNetwork',
1107                           'prefer-network-wifi',
1108                           'Options_NetworkSetPrefer');
1109      sendCheckedIfEnabled(servicePath,
1110                           'setAutoConnect',
1111                           'auto-connect-network-wifi',
1112                           'Options_NetworkAutoConnect');
1113    } else if (type == 'WiMAX') {
1114      sendCheckedIfEnabled(servicePath,
1115                           'setAutoConnect',
1116                           'auto-connect-network-wimax',
1117                           'Options_NetworkAutoConnect');
1118    } else if (type == 'Cellular') {
1119      sendCheckedIfEnabled(servicePath,
1120                           'setAutoConnect',
1121                           'auto-connect-network-cellular',
1122                           'Options_NetworkAutoConnect');
1123    } else if (type == 'VPN') {
1124      chrome.send('setServerHostname',
1125                  [servicePath, $('inet-server-hostname').value]);
1126      sendCheckedIfEnabled(servicePath,
1127                           'setAutoConnect',
1128                           'auto-connect-network-vpn',
1129                           'Options_NetworkAutoConnect');
1130    }
1131
1132    var nameServerTypes = ['automatic', 'google', 'user'];
1133    var nameServerType = 'automatic';
1134    for (var i = 0; i < nameServerTypes.length; ++i) {
1135      if ($(nameServerTypes[i] + '-dns-radio').checked) {
1136        nameServerType = nameServerTypes[i];
1137        break;
1138      }
1139    }
1140    detailsPage.sendIpConfig_(nameServerType);
1141
1142    PageManager.closeOverlay();
1143  };
1144
1145  /**
1146   * Event handler called when the name server type changes.
1147   * @param {string} type The selected name sever type, 'automatic', 'google',
1148   *                      or 'user'.
1149   */
1150  DetailsInternetPage.updateNameServerDisplay = function(type) {
1151    var editable = type == 'user';
1152    var fields = [$('ipconfig-dns1'), $('ipconfig-dns2'),
1153                  $('ipconfig-dns3'), $('ipconfig-dns4')];
1154    for (var i = 0; i < fields.length; ++i) {
1155      fields[i].editable = editable;
1156    }
1157    if (editable)
1158      $('ipconfig-dns1').focus();
1159
1160    var automaticDns = $('automatic-dns-display');
1161    var googleDns = $('google-dns-display');
1162    var userDns = $('user-dns-settings');
1163    switch (type) {
1164      case 'automatic':
1165        automaticDns.setAttribute('selected', '');
1166        googleDns.removeAttribute('selected');
1167        userDns.removeAttribute('selected');
1168        break;
1169      case 'google':
1170        automaticDns.removeAttribute('selected');
1171        googleDns.setAttribute('selected', '');
1172        userDns.removeAttribute('selected');
1173        break;
1174      case 'user':
1175        automaticDns.removeAttribute('selected');
1176        googleDns.removeAttribute('selected');
1177        userDns.setAttribute('selected', '');
1178        break;
1179    }
1180  };
1181
1182  /**
1183   * Method called from Chrome with a dictionary of non ONC configuration
1184   * properties, including the HUID and service path to be used for requesting
1185   * the ONC properties. Note: currently GUID is only used to confirm that the
1186   * selected network still exists. It will be used instead of servicePath
1187   * once switching to the networkingPrivate API (see TODO below).
1188   * @param {InternetDetailedInfo} info
1189   */
1190  DetailsInternetPage.showDetailedInfo = function(info) {
1191    if (!('GUID' in info)) {
1192      // No network was found for, close the overlay.
1193      PageManager.closeOverlay();
1194      return;
1195    }
1196    var detailsPage = DetailsInternetPage.getInstance();
1197    detailsPage.servicePath_ = info.servicePath;
1198    detailsPage.showCarrierSelect_ = info.showCarrierSelect;
1199    detailsPage.showViewAccountButton_ = info.showViewAccountButton;
1200    // Ask Chrome to call sendNetworkDetails with the ONC properties.
1201    // TODO(stevenjb): Use networkingPrivate.getManagedProperties(info.guid).
1202    chrome.send('getManagedProperties', [info.servicePath]);
1203  };
1204
1205  /**
1206   * Method called from Chrome when the ONC properties for the displayed
1207   * network may have changed.
1208   * @param {Object} update The updated ONC dictionary for the network.
1209   */
1210  DetailsInternetPage.updateConnectionData = function(oncData) {
1211    var detailsPage = DetailsInternetPage.getInstance();
1212    if (!detailsPage.visible)
1213      return;
1214
1215    if (oncData.servicePath != detailsPage.servicePath_)
1216      return;
1217
1218    // Update our cached data object.
1219    detailsPage.onc_ = new OncData(oncData);
1220
1221    detailsPage.populateHeader_();
1222    detailsPage.updateConnectionButtonVisibilty_();
1223    detailsPage.updateDetails_();
1224  };
1225
1226  /**
1227   * Method called from Chrome when the initial dictionary of ONC configuration
1228   * properties is available.
1229   * @param {Object} oncData Dictionary of ONC properties.
1230   */
1231  DetailsInternetPage.sendNetworkDetails = function(oncData) {
1232    var onc = new OncData(oncData);
1233
1234    var detailsPage = DetailsInternetPage.getInstance();
1235    detailsPage.onc_ = onc;
1236    var type = onc.getActiveValue('Type');
1237    detailsPage.type_ = type;
1238
1239    sendShowDetailsMetrics(type, onc.getActiveValue('ConnectionState'));
1240
1241    detailsPage.populateHeader_();
1242    detailsPage.updateConnectionButtonVisibilty_();
1243    detailsPage.updateDetails_();
1244
1245    // TODO(stevenjb): Some of the setup below should be moved to
1246    // updateDetails_() so that updates are reflected in the UI.
1247
1248    // Only show proxy for remembered networks.
1249    var remembered = onc.getSource() != 'None';
1250    if (remembered) {
1251      detailsPage.showProxy_ = true;
1252      // Inform Chrome which network to use for proxy configuration.
1253      chrome.send('selectNetwork', [detailsPage.servicePath_]);
1254    } else {
1255      detailsPage.showProxy_ = false;
1256    }
1257
1258    $('web-proxy-auto-discovery').hidden = true;
1259
1260    var restricted = onc.getActiveValue('RestrictedConnectivity');
1261    var restrictedString = loadTimeData.getString(
1262        restricted ? 'restrictedYes' : 'restrictedNo');
1263
1264    var inetAddress = {};
1265    var inetNetmask = {};
1266    var inetGateway = {};
1267
1268    var inetNameServersString;
1269
1270    var ipconfigList = onc.getActiveValue('IPConfigs');
1271    if (Array.isArray(ipconfigList)) {
1272      for (var i = 0; i < ipconfigList.length; ++i) {
1273        var ipconfig = ipconfigList[i];
1274        var ipType = ipconfig['Type'];
1275        if (ipType != 'IPv4') {
1276          // TODO(stevenjb): Handle IPv6 properties.
1277          continue;
1278        }
1279        var address = ipconfig['IPAddress'];
1280        inetAddress.automatic = address;
1281        inetAddress.value = address;
1282        var netmask = prefixLengthToNetmask(ipconfig['RoutingPrefix']);
1283        inetNetmask.automatic = netmask;
1284        inetNetmask.value = netmask;
1285        var gateway = ipconfig['Gateway'];
1286        inetGateway.automatic = gateway;
1287        inetGateway.value = gateway;
1288        if ('WebProxyAutoDiscoveryUrl' in ipconfig) {
1289          $('web-proxy-auto-discovery').hidden = false;
1290          $('web-proxy-auto-discovery-url').value =
1291              ipconfig['WebProxyAutoDiscoveryUrl'];
1292        }
1293        if ('NameServers' in ipconfig) {
1294          var inetNameServers = ipconfig['NameServers'];
1295          inetNameServers = inetNameServers.sort();
1296          inetNameServersString = inetNameServers.join(',');
1297        }
1298        break;  // Use the first IPv4 entry.
1299      }
1300    }
1301
1302    // Override the "automatic" values with the real saved DHCP values,
1303    // if they are set.
1304    var savedNameServersString;
1305    var savedIpAddress = onc.getActiveValue('SavedIPConfig.IPAddress');
1306    if (savedIpAddress != undefined) {
1307      inetAddress.automatic = savedIpAddress;
1308      inetAddress.value = savedIpAddress;
1309    }
1310    var savedPrefix = onc.getActiveValue('SavedIPConfig.RoutingPrefix');
1311    if (savedPrefix != undefined) {
1312      var savedNetmask = prefixLengthToNetmask(savedPrefix);
1313      inetNetmask.automatic = savedNetmask;
1314      inetNetmask.value = savedNetmask;
1315    }
1316    var savedGateway = onc.getActiveValue('SavedIPConfig.Gateway');
1317    if (savedGateway != undefined) {
1318      inetGateway.automatic = savedGateway;
1319      inetGateway.value = savedGateway;
1320    }
1321    var savedNameServers = onc.getActiveValue('SavedIPConfig.NameServers');
1322    if (savedNameServers) {
1323      savedNameServers = savedNameServers.sort();
1324      savedNameServersString = savedNameServers.join(',');
1325    }
1326
1327    var ipAutoConfig = 'automatic';
1328
1329    var staticNameServersString;
1330    var staticIpAddress = onc.getActiveValue('StaticIPConfig.IPAddress');
1331    if (staticIpAddress != undefined) {
1332      ipAutoConfig = 'user';
1333      inetAddress.user = staticIpAddress;
1334      inetAddress.value = staticIpAddress;
1335    }
1336    var staticPrefix = onc.getActiveValue('StaticIPConfig.RoutingPrefix');
1337    if (staticPrefix != undefined) {
1338      var staticNetmask = prefixLengthToNetmask(staticPrefix);
1339      inetNetmask.user = staticNetmask;
1340      inetNetmask.value = staticNetmask;
1341    }
1342    var staticGateway = onc.getActiveValue('StaticIPConfig.Gateway');
1343    if (staticGateway != undefined) {
1344      inetGateway.user = staticGateway;
1345      inetGateway.value = staticGateway;
1346    }
1347    var staticNameServers = onc.getActiveValue('StaticIPConfig.NameServers');
1348    if (staticNameServers) {
1349      staticNameServers = staticNameServers.sort();
1350      staticNameServersString = staticNameServers.join(',');
1351    }
1352
1353    $('ip-automatic-configuration-checkbox').checked =
1354        ipAutoConfig == 'automatic';
1355
1356    inetAddress.autoConfig = ipAutoConfig;
1357    inetNetmask.autoConfig = ipAutoConfig;
1358    inetGateway.autoConfig = ipAutoConfig;
1359
1360    var configureAddressField = function(field, model) {
1361      IPAddressField.decorate(field);
1362      field.model = model;
1363      field.editable = model.autoConfig == 'user';
1364    };
1365    configureAddressField($('ip-address'), inetAddress);
1366    configureAddressField($('ip-netmask'), inetNetmask);
1367    configureAddressField($('ip-gateway'), inetGateway);
1368
1369    // Set Nameserver fields.
1370    var nameServerType = 'automatic';
1371    if (staticNameServersString) {
1372      // If static nameservers are defined and match the google name servers,
1373      // show that in the UI, otherwise show the custom static nameservers.
1374      if (staticNameServersString == GoogleNameServersString)
1375        nameServerType = 'google';
1376      else if (staticNameServersString == inetNameServersString)
1377        nameServerType = 'user';
1378    }
1379    if (nameServerType == 'automatic')
1380      $('automatic-dns-display').textContent = inetNameServersString;
1381    else
1382      $('automatic-dns-display').textContent = savedNameServersString;
1383    $('google-dns-display').textContent = GoogleNameServersString;
1384
1385    var nameServersUser = [];
1386    if (staticNameServers) {
1387      nameServersUser = staticNameServers;
1388    } else if (savedNameServers) {
1389      // Pre-populate with values provided by DHCP server.
1390      nameServersUser = savedNameServers;
1391    }
1392
1393    var nameServerModels = [];
1394    for (var i = 0; i < 4; ++i)
1395      nameServerModels.push({value: nameServersUser[i] || ''});
1396
1397    $(nameServerType + '-dns-radio').checked = true;
1398    configureAddressField($('ipconfig-dns1'), nameServerModels[0]);
1399    configureAddressField($('ipconfig-dns2'), nameServerModels[1]);
1400    configureAddressField($('ipconfig-dns3'), nameServerModels[2]);
1401    configureAddressField($('ipconfig-dns4'), nameServerModels[3]);
1402
1403    DetailsInternetPage.updateNameServerDisplay(nameServerType);
1404
1405    var macAddress = onc.getActiveValue('MacAddress');
1406    if (macAddress) {
1407      $('hardware-address').textContent = macAddress;
1408      $('hardware-address-row').style.display = 'table-row';
1409    } else {
1410      // This is most likely a device without a hardware address.
1411      $('hardware-address-row').style.display = 'none';
1412    }
1413
1414    var setOrHideParent = function(field, property) {
1415      if (property != undefined) {
1416        $(field).textContent = property;
1417        $(field).parentElement.hidden = false;
1418      } else {
1419        $(field).parentElement.hidden = true;
1420      }
1421    };
1422
1423    var networkName = onc.getTranslatedValue('Name');
1424
1425    // Signal strength as percentage (for WiFi and WiMAX).
1426    var signalStrength;
1427    if (type == 'WiFi' || type == 'WiMAX')
1428      signalStrength = onc.getActiveValue(type + '.SignalStrength');
1429    if (!signalStrength)
1430      signalStrength = 0;
1431    var strengthFormat = loadTimeData.getString('inetSignalStrengthFormat');
1432    var strengthString = strengthFormat.replace('$1', signalStrength);
1433
1434    if (type == 'WiFi') {
1435      OptionsPage.showTab($('wifi-network-nav-tab'));
1436      $('wifi-restricted-connectivity').textContent = restrictedString;
1437      var ssid = onc.getActiveValue('WiFi.SSID');
1438      $('wifi-ssid').textContent = ssid ? ssid : networkName;
1439      setOrHideParent('wifi-bssid', onc.getActiveValue('WiFi.BSSID'));
1440      var security = onc.getWiFiSecurity();
1441      if (security == 'None')
1442        security = undefined;
1443      setOrHideParent('wifi-security', security);
1444      // Frequency is in MHz.
1445      var frequency = onc.getActiveValue('WiFi.Frequency');
1446      if (!frequency)
1447        frequency = 0;
1448      var frequencyFormat = loadTimeData.getString('inetFrequencyFormat');
1449      frequencyFormat = frequencyFormat.replace('$1', frequency);
1450      $('wifi-frequency').textContent = frequencyFormat;
1451      $('wifi-signal-strength').textContent = strengthString;
1452      setOrHideParent('wifi-hardware-address',
1453                      onc.getActiveValue('MacAddress'));
1454      var priority = onc.getActiveValue('Priority');
1455      $('prefer-network-wifi').checked = priority > 0;
1456      $('prefer-network-wifi').disabled = !remembered;
1457      $('auto-connect-network-wifi').checked =
1458          onc.getActiveValue('WiFi.AutoConnect');
1459      $('auto-connect-network-wifi').disabled = !remembered;
1460    } else if (type == 'WiMAX') {
1461      OptionsPage.showTab($('wimax-network-nav-tab'));
1462      $('wimax-restricted-connectivity').textContent = restrictedString;
1463
1464      $('auto-connect-network-wimax').checked =
1465          onc.getActiveValue('WiMAX.AutoConnect');
1466      $('auto-connect-network-wimax').disabled = !remembered;
1467      var identity = onc.getActiveValue('WiMAX.EAP.Identity');
1468      setOrHideParent('wimax-eap-identity', identity);
1469      $('wimax-signal-strength').textContent = strengthString;
1470    } else if (type == 'Cellular') {
1471      OptionsPage.showTab($('cellular-conn-nav-tab'));
1472
1473      var isGsm = onc.getActiveValue('Cellular.Family') == 'GSM';
1474
1475      var currentCarrierIndex = -1;
1476      if (this.showCarrierSelect_) {
1477        var currentCarrier =
1478            isGsm ? CarrierGenericUMTS : onc.getActiveValue('Cellular.Carrier');
1479        var supportedCarriers =
1480            onc.getActiveValue('Cellular.SupportedCarriers');
1481        for (var c1 = 0; c1 < supportedCarriers.length; ++c1) {
1482          if (supportedCarriers[c1] == currentCarrier) {
1483            currentCarrierIndex = c1;
1484            break;
1485          }
1486        }
1487        if (currentCarrierIndex != -1) {
1488          var carrierSelector = $('select-carrier');
1489          carrierSelector.onchange = DetailsInternetPage.handleCarrierChanged;
1490          carrierSelector.options.length = 0;
1491          for (var c2 = 0; c2 < supportedCarriers.length; ++c2) {
1492            var option = document.createElement('option');
1493            option.textContent = supportedCarriers[c2];
1494            carrierSelector.add(option);
1495          }
1496          carrierSelector.selectedIndex = currentCarrierIndex;
1497        }
1498      }
1499      if (currentCarrierIndex == -1)
1500        $('service-name').textContent = networkName;
1501
1502      $('network-technology').textContent =
1503          onc.getActiveValue('Cellular.NetworkTechnology');
1504      $('roaming-state').textContent =
1505          onc.getTranslatedValue('Cellular.RoamingState');
1506      $('cellular-restricted-connectivity').textContent = restrictedString;
1507      // 'errorMessage' is a non ONC property added by Chrome.
1508      $('error-state').textContent = onc.getActiveValue('errorMessage');
1509      $('manufacturer').textContent =
1510          onc.getActiveValue('Cellular.Manufacturer');
1511      $('model-id').textContent = onc.getActiveValue('Cellular.ModelID');
1512      $('firmware-revision').textContent =
1513          onc.getActiveValue('Cellular.FirmwareRevision');
1514      $('hardware-revision').textContent =
1515          onc.getActiveValue('Cellular.HardwareRevision');
1516      $('mdn').textContent = onc.getActiveValue('Cellular.MDN');
1517
1518      // Show ServingOperator properties only if available.
1519      var servingOperatorName =
1520          onc.getActiveValue('Cellular.ServingOperator.Name');
1521      var servingOperatorCode =
1522          onc.getActiveValue('Cellular.ServingOperator.Code');
1523      if (servingOperatorName != undefined &&
1524          servingOperatorCode != undefined) {
1525        $('operator-name').textContent = servingOperatorName;
1526        $('operator-code').textContent = servingOperatorCode;
1527      } else {
1528        $('operator-name').parentElement.hidden = true;
1529        $('operator-code').parentElement.hidden = true;
1530      }
1531      // Make sure that GSM/CDMA specific properties that shouldn't be hidden
1532      // are visible.
1533      updateHidden('#details-internet-page .gsm-only', false);
1534      updateHidden('#details-internet-page .cdma-only', false);
1535
1536      // Show IMEI/ESN/MEID/MIN/PRL only if they are available.
1537      setOrHideParent('esn', onc.getActiveValue('Cellular.ESN'));
1538      setOrHideParent('imei', onc.getActiveValue('Cellular.IMEI'));
1539      setOrHideParent('meid', onc.getActiveValue('Cellular.MEID'));
1540      setOrHideParent('min', onc.getActiveValue('Cellular.MIN'));
1541      setOrHideParent('prl-version', onc.getActiveValue('Cellular.PRLVersion'));
1542
1543      if (isGsm) {
1544        $('iccid').textContent = onc.getActiveValue('Cellular.ICCID');
1545        $('imsi').textContent = onc.getActiveValue('Cellular.IMSI');
1546        detailsPage.initializeApnList_();
1547      }
1548      $('auto-connect-network-cellular').checked =
1549          onc.getActiveValue('Cellular.AutoConnect');
1550      $('auto-connect-network-cellular').disabled = false;
1551    } else if (type == 'VPN') {
1552      OptionsPage.showTab($('vpn-nav-tab'));
1553      $('inet-service-name').textContent = networkName;
1554      $('inet-provider-type').textContent =
1555          onc.getTranslatedValue('VPN.Type');
1556      var providerType = onc.getActiveValue('VPN.Type');
1557      var usernameKey;
1558      if (providerType == 'OpenVPN')
1559        usernameKey = 'VPN.OpenVPN.Username';
1560      else if (providerType == 'L2TP-IPsec')
1561        usernameKey = 'VPN.L2TP.Username';
1562
1563      if (usernameKey) {
1564        $('inet-username').parentElement.hidden = false;
1565        $('inet-username').textContent = onc.getActiveValue(usernameKey);
1566      } else {
1567        $('inet-username').parentElement.hidden = true;
1568      }
1569      var inetServerHostname = $('inet-server-hostname');
1570      inetServerHostname.value = onc.getActiveValue('VPN.Host');
1571      inetServerHostname.resetHandler = function() {
1572        PageManager.hideBubble();
1573        var recommended = onc.getRecommendedValue('VPN.Host');
1574        if (recommended != undefined)
1575          inetServerHostname.value = recommended;
1576      };
1577      $('auto-connect-network-vpn').checked =
1578          onc.getActiveValue('VPN.AutoConnect');
1579      $('auto-connect-network-vpn').disabled = false;
1580    } else {
1581      OptionsPage.showTab($('internet-nav-tab'));
1582    }
1583
1584    // Update controlled option indicators.
1585    var indicators = cr.doc.querySelectorAll(
1586        '#details-internet-page .controlled-setting-indicator');
1587    for (var i = 0; i < indicators.length; i++) {
1588      var managed = indicators[i].hasAttribute('managed');
1589      // TODO(stevenjb): Eliminate support for 'data' once 39 is stable.
1590      var attributeName = managed ? 'managed' : 'data';
1591      var propName = indicators[i].getAttribute(attributeName);
1592      if (!propName)
1593        continue;
1594      var propValue = managed ?
1595          onc.getManagedProperty(propName) :
1596          onc.getActiveValue(propName);
1597      // If the property is unset or unmanaged (i.e. not an Object) skip it.
1598      if (propValue == undefined || (typeof propValue != 'object'))
1599        continue;
1600      var event;
1601      if (managed)
1602        event = detailsPage.createManagedEvent_(propName, propValue);
1603      else
1604        event = detailsPage.createControlledEvent_(propName,
1605            /** @type {{value: *, controlledBy: *, recommendedValue: *}} */(
1606                propValue));
1607      indicators[i].handlePrefChange(event);
1608      var forElement = $(indicators[i].getAttribute('for'));
1609      if (forElement) {
1610        if (event.value.controlledBy == 'policy')
1611          forElement.disabled = true;
1612        if (forElement.resetHandler)
1613          indicators[i].resetHandler = forElement.resetHandler;
1614      }
1615    }
1616
1617    detailsPage.updateControls();
1618
1619    // Don't show page name in address bar and in history to prevent people
1620    // navigate here by hand and solve issue with page session restore.
1621    PageManager.showPageByName('detailsInternetPage', false);
1622  };
1623
1624  return {
1625    DetailsInternetPage: DetailsInternetPage
1626  };
1627});
1628