summaryrefslogtreecommitdiff
path: root/chromium/chrome/browser/resources/options/chromeos
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/chrome/browser/resources/options/chromeos')
-rw-r--r--chromium/chrome/browser/resources/options/chromeos/accounts_options_page.css16
-rw-r--r--chromium/chrome/browser/resources/options/chromeos/accounts_user_list.js2
-rw-r--r--chromium/chrome/browser/resources/options/chromeos/bluetooth_add_device_overlay.js2
-rw-r--r--chromium/chrome/browser/resources/options/chromeos/bluetooth_device_list.js3
-rw-r--r--chromium/chrome/browser/resources/options/chromeos/bluetooth_pair_device_overlay.js4
-rw-r--r--chromium/chrome/browser/resources/options/chromeos/change_picture_options.css6
-rw-r--r--chromium/chrome/browser/resources/options/chromeos/change_picture_options.js12
-rw-r--r--chromium/chrome/browser/resources/options/chromeos/display_options.css20
-rw-r--r--chromium/chrome/browser/resources/options/chromeos/display_options.html20
-rw-r--r--chromium/chrome/browser/resources/options/chromeos/display_options.js240
-rw-r--r--chromium/chrome/browser/resources/options/chromeos/display_overscan.css12
-rw-r--r--chromium/chrome/browser/resources/options/chromeos/internet_detail.css8
-rw-r--r--chromium/chrome/browser/resources/options/chromeos/internet_detail.html48
-rw-r--r--chromium/chrome/browser/resources/options/chromeos/internet_detail.js758
-rw-r--r--chromium/chrome/browser/resources/options/chromeos/keyboard_overlay.js6
-rw-r--r--chromium/chrome/browser/resources/options/chromeos/network_list.js773
-rw-r--r--chromium/chrome/browser/resources/options/chromeos/onc_data.js13
-rw-r--r--chromium/chrome/browser/resources/options/chromeos/preferred_networks.js13
-rw-r--r--chromium/chrome/browser/resources/options/chromeos/vpn_providers.js123
19 files changed, 1411 insertions, 668 deletions
diff --git a/chromium/chrome/browser/resources/options/chromeos/accounts_options_page.css b/chromium/chrome/browser/resources/options/chromeos/accounts_options_page.css
index bba94eacfa5..365775759e5 100644
--- a/chromium/chrome/browser/resources/options/chromeos/accounts_options_page.css
+++ b/chromium/chrome/browser/resources/options/chromeos/accounts_options_page.css
@@ -24,13 +24,9 @@
width: 26px;
}
-.user-email-label {
- -webkit-margin-start: 10px;
-}
-
+.user-email-label,
.user-name-label {
-webkit-margin-start: 10px;
- color: darkgray;
}
.user-email-name-block {
@@ -43,17 +39,17 @@
.remove-user-button {
background-image: -webkit-image-set(
- url('../../../../../ui/resources/default_100_percent/close_2.png') 1x,
- url('../../../../../ui/resources/default_200_percent/close_2.png') 2x);
+ url(../../../../../ui/resources/default_100_percent/close_2.png) 1x,
+ url(../../../../../ui/resources/default_200_percent/close_2.png) 2x);
height: 16px;
width: 16px;
}
.remove-user-button:hover {
background-image: -webkit-image-set(
- url('../../../../../ui/resources/default_100_percent/close_2_hover.png')
+ url(../../../../../ui/resources/default_100_percent/close_2_hover.png)
1x,
- url('../../../../../ui/resources/default_200_percent/close_2_hover.png')
+ url(../../../../../ui/resources/default_200_percent/close_2_hover.png)
2x);
}
@@ -85,7 +81,7 @@
#ownerOnlyWarning {
-webkit-padding-start: 20px;
- background-image: url('warning.png');
+ background-image: url(warning.png);
background-repeat: no-repeat;
margin-bottom: 10px;
margin-top: 10px;
diff --git a/chromium/chrome/browser/resources/options/chromeos/accounts_user_list.js b/chromium/chrome/browser/resources/options/chromeos/accounts_user_list.js
index 018f63cf768..8bb3e3f0fbe 100644
--- a/chromium/chrome/browser/resources/options/chromeos/accounts_user_list.js
+++ b/chromium/chrome/browser/resources/options/chromeos/accounts_user_list.js
@@ -81,7 +81,7 @@ cr.define('options.accounts', function() {
/**
* Loads given user list.
- * @param {!Array.<Object>} users An array of user info objects.
+ * @param {!Array<Object>} users An array of user info objects.
* @private
*/
load_: function(users) {
diff --git a/chromium/chrome/browser/resources/options/chromeos/bluetooth_add_device_overlay.js b/chromium/chrome/browser/resources/options/chromeos/bluetooth_add_device_overlay.js
index fa91e6919c2..675e08772c9 100644
--- a/chromium/chrome/browser/resources/options/chromeos/bluetooth_add_device_overlay.js
+++ b/chromium/chrome/browser/resources/options/chromeos/bluetooth_add_device_overlay.js
@@ -42,6 +42,8 @@ cr.define('options', function() {
var self = this;
$('bluetooth-add-device-apply-button').onclick = function(event) {
+ chrome.send('coreOptionsUserMetricsAction',
+ ['Options_BluetoothConnectNewDevice']);
var device = self.deviceList_.selectedItem;
var address = device.address;
PageManager.closeOverlay();
diff --git a/chromium/chrome/browser/resources/options/chromeos/bluetooth_device_list.js b/chromium/chrome/browser/resources/options/chromeos/bluetooth_device_list.js
index 8aa6f88018e..7db87b0e94d 100644
--- a/chromium/chrome/browser/resources/options/chromeos/bluetooth_device_list.js
+++ b/chromium/chrome/browser/resources/options/chromeos/bluetooth_device_list.js
@@ -299,6 +299,9 @@ cr.define('options.system.bluetooth', function() {
// forgetting the device.
chrome.send('updateBluetoothDevice',
[item.data.address, item.connected ? 'disconnect' : 'forget']);
+
+ chrome.send('coreOptionsUserMetricsAction',
+ ['Options_BluetoothRemoveDevice']);
}
},
diff --git a/chromium/chrome/browser/resources/options/chromeos/bluetooth_pair_device_overlay.js b/chromium/chrome/browser/resources/options/chromeos/bluetooth_pair_device_overlay.js
index 35c5b20e91d..63b9ee4a708 100644
--- a/chromium/chrome/browser/resources/options/chromeos/bluetooth_pair_device_overlay.js
+++ b/chromium/chrome/browser/resources/options/chromeos/bluetooth_pair_device_overlay.js
@@ -27,7 +27,7 @@ cr.define('options', function() {
/**
* List of IDs for conditionally visible elements in the dialog.
- * @type {Array.<string>}
+ * @type {Array<string>}
* @const
*/
var ELEMENTS = ['bluetooth-pairing-passkey-display',
@@ -233,7 +233,7 @@ cr.define('options', function() {
/**
* Updates the visibility of elements in the dialog.
- * @param {Array.<string>} list List of conditionally visible elements that
+ * @param {Array<string>} list List of conditionally visible elements that
* are to be made visible.
* @private
*/
diff --git a/chromium/chrome/browser/resources/options/chromeos/change_picture_options.css b/chromium/chrome/browser/resources/options/chromeos/change_picture_options.css
index d68291a6e9c..9ca91f86f46 100644
--- a/chromium/chrome/browser/resources/options/chromeos/change_picture_options.css
+++ b/chromium/chrome/browser/resources/options/chromeos/change_picture_options.css
@@ -141,7 +141,7 @@
#flip-photo {
-webkit-transition: opacity 75ms linear;
- background: url('chrome://theme/IDR_MIRROR_FLIP') no-repeat;
+ background: url(chrome://theme/IDR_MIRROR_FLIP) no-repeat;
border: none;
bottom: 44px; /* 8px + image bottom. */
display: block;
@@ -178,13 +178,13 @@ html[dir=rtl] #flip-photo {
}
.camera:not(.live) #discard-photo {
- background: url('chrome://theme/IDR_USER_IMAGE_RECYCLE')
+ background: url(chrome://theme/IDR_USER_IMAGE_RECYCLE)
no-repeat center center;
display: block;
}
.camera.live.online #take-photo {
- background: url('chrome://theme/IDR_USER_IMAGE_CAPTURE')
+ background: url(chrome://theme/IDR_USER_IMAGE_CAPTURE)
no-repeat center -1px;
display: block;
}
diff --git a/chromium/chrome/browser/resources/options/chromeos/change_picture_options.js b/chromium/chrome/browser/resources/options/chromeos/change_picture_options.js
index 506e483c12d..de6670a4c7b 100644
--- a/chromium/chrome/browser/resources/options/chromeos/change_picture_options.js
+++ b/chromium/chrome/browser/resources/options/chromeos/change_picture_options.js
@@ -10,7 +10,7 @@ cr.define('options', function() {
/**
* Array of button URLs used on this page.
- * @type {Array.<string>}
+ * @type {Array<string>}
* @const
*/
var ButtonImageUrls = [
@@ -303,19 +303,13 @@ cr.define('options', function() {
/**
* Appends default images to the image grid. Should only be called once.
- * @param {Array.<{url: string, author: string, website: string}>}
+ * @param {Array<{url: string, author: string, website: string}>}
* imagesData An array of default images data, including URL, author and
* website.
* @private
*/
setDefaultImages_: function(imagesData) {
- var imageGrid = $('user-image-grid');
- for (var i = 0, data; data = imagesData[i]; i++) {
- var item = imageGrid.addItem(data.url, data.title);
- item.type = 'default';
- item.author = data.author || '';
- item.website = data.website || '';
- }
+ $('user-image-grid').setDefaultImages(imagesData);
},
};
diff --git a/chromium/chrome/browser/resources/options/chromeos/display_options.css b/chromium/chrome/browser/resources/options/chromeos/display_options.css
index 3f738791e5c..73a78e45833 100644
--- a/chromium/chrome/browser/resources/options/chromeos/display_options.css
+++ b/chromium/chrome/browser/resources/options/chromeos/display_options.css
@@ -20,16 +20,10 @@
width: 100%;
}
-#display-options-displays-view-mirroring {
- margin: 20px 0 20px 0;
-}
-
#display-configurations {
-webkit-padding-end: 0;
-webkit-padding-start: 15px;
- background-color: white;
border-top: 1px solid lightgrey;
- padding-bottom: 15px;
padding-top: 15px;
}
@@ -38,7 +32,6 @@
* upper-half, which were left/top before the rotation. */
#display-configuration-arrow {
-webkit-transform: rotate(45deg);
- background-color: white;
border-left: 1px solid lightgrey;
border-top: 1px solid lightgrey;
height: 20px;
@@ -47,6 +40,19 @@
z-index: 1;
}
+#display-configurations,
+#display-configuration-arrow,
+#display-options-page .action-area {
+ background-color: white;
+}
+
+#display-options-page .action-area {
+ /* Because this element has a background-color, we need to emulate the
+ * parent's border-radius (otherwise there's sharp corners). */
+ border-bottom-left-radius: inherit;
+ border-bottom-right-radius: inherit;
+}
+
#selected-display-data-container {
z-index: 2;
}
diff --git a/chromium/chrome/browser/resources/options/chromeos/display_options.html b/chromium/chrome/browser/resources/options/chromeos/display_options.html
index 87d23de74c5..8e1f9d049b6 100644
--- a/chromium/chrome/browser/resources/options/chromeos/display_options.html
+++ b/chromium/chrome/browser/resources/options/chromeos/display_options.html
@@ -16,6 +16,18 @@
</button>
<button id="display-options-set-primary"
class="display-options-button" i18n-content="setPrimary">
+ </button>
+ </div>
+ <div id="display-options-unified-desktop"
+ class="checkbox selected-display-option-row" hidden>
+ <!-- intentionally blank for the title column space. -->
+ <div class="selected-display-option-title">
+ </div>
+ <label>
+ <input id="display-options-toggle-unified-desktop" type="checkbox">
+ <span class="controlled-setting-with-label"
+ i18n-content="enableUnifiedDesktop"></span>
+ </label>
</div>
<div class="selected-display-option-row">
<div class="selected-display-option-title"
@@ -47,7 +59,7 @@
</button>
</div>
<div class="selected-display-option-row"
- id="selected-display-color-profile-row">
+ id="selected-display-color-profile-row" hidden>
<div class="selected-display-option-title"
i18n-content="selectedDisplayColorProfile">
</div>
@@ -62,4 +74,10 @@
<div id="display-configuration-arrow">
</div>
</div>
+ <div class="action-area">
+ <div class="button-strip">
+ <button id="display-options-done" i18n-content="done"
+ class="default-button"></button>
+ </div>
+ </div>
</div>
diff --git a/chromium/chrome/browser/resources/options/chromeos/display_options.js b/chromium/chrome/browser/resources/options/chromeos/display_options.js
index 756e564534b..bf316214fe8 100644
--- a/chromium/chrome/browser/resources/options/chromeos/display_options.js
+++ b/chromium/chrome/browser/resources/options/chromeos/display_options.js
@@ -6,13 +6,13 @@ cr.exportPath('options');
/**
* @typedef {{
- * availableColorProfiles: Array.<{profileId: number, name: string}>,
+ * availableColorProfiles: Array<{profileId: number, name: string}>,
* colorProfile: number,
* height: number,
* id: string,
* isInternal: boolean,
* isPrimary: boolean,
- * resolutions: Array.<{width: number, height: number, originalWidth: number,
+ * resolutions: Array<{width: number, height: number, originalWidth: number,
* originalHeight: number, deviceScaleFactor: number, scale: number,
* refreshRate: number, isBest: boolean, selected: boolean}>,
* name: string,
@@ -36,6 +36,17 @@ options.SecondaryDisplayLayout = {
LEFT: 3
};
+/**
+ * Enumeration of multi display mode. The value has to be same as the
+ * values in ash/display/display_manager..
+ * @enum {number}
+ */
+options.MultiDisplayMode = {
+ EXTENDED: 0,
+ MIRRORING: 1,
+ UNIFIED: 2,
+};
+
cr.define('options', function() {
var Page = cr.ui.pageManager.Page;
var PageManager = cr.ui.pageManager.PageManager;
@@ -116,6 +127,18 @@ cr.define('options', function() {
*/
mirroring_: false,
+ /*
+ * Whether the unified desktop is enable or not.
+ * @private
+ */
+ unifiedDesktopEnabled_: false,
+
+ /*
+ * Whether the unified desktop option should be present.
+ * @private
+ */
+ showUnifiedDesktopOption_: false,
+
/**
* The current secondary display layout.
* @private
@@ -125,7 +148,7 @@ cr.define('options', function() {
/**
* The array of current output displays. It also contains the display
* rectangles currently rendered on screen.
- * @type {Array.<options.DisplayInfo>}
+ * @type {Array<options.DisplayInfo>}
* @private
*/
displays_: [],
@@ -170,6 +193,12 @@ cr.define('options', function() {
*/
lastTouchLocation_: null,
+ /**
+ * Whether the display settings can be shown.
+ * @private
+ */
+ enabled_: true,
+
/** @override */
initializePage: function() {
Page.prototype.initializePage.call(this);
@@ -210,6 +239,16 @@ cr.define('options', function() {
chrome.send('coreOptionsUserMetricsAction',
['Options_DisplaySetOverscan']);
}).bind(this);
+
+ $('display-options-done').onclick = function() {
+ PageManager.closeOverlay();
+ };
+
+ $('display-options-toggle-unified-desktop').onclick = (function() {
+ this.unifiedDesktopEnabled_ = !this.unifiedDesktopEnabled_;
+ chrome.send('setUnifiedDesktopEnabled',
+ [this.unifiedDesktopEnabled_]);
+ }).bind(this);
},
/** @override */
@@ -224,6 +263,29 @@ cr.define('options', function() {
chrome.send('getDisplayInfo');
},
+ /** @override */
+ canShowPage: function() {
+ return this.enabled_;
+ },
+
+ /**
+ * Enables or disables the page. When disabled, the page will not be able to
+ * open, and will close if currently opened.
+ * @param {boolean} enabled Whether the page should be enabled.
+ * @param {boolean} showUnifiedDesktop Whether the unified desktop option
+ * should be present.
+ */
+ setEnabled: function(enabled, showUnifiedDesktop) {
+ if (this.enabled_ == enabled &&
+ this.showUnifiedDesktopOption_ == showUnifiedDesktop) {
+ return;
+ }
+ this.enabled_ = enabled;
+ this.showUnifiedDesktopOption_ = showUnifiedDesktop;
+ if (!enabled && this.visible)
+ PageManager.closeOverlay();
+ },
+
/**
* Mouse move handler for dragging display rectangle.
* @param {Event} e The mouse move event.
@@ -743,8 +805,6 @@ cr.define('options', function() {
var totalHeight = height + numDisplays * MIRRORING_OFFSET_PIXELS;
this.displaysView_.style.height = totalHeight + 'px';
- this.displaysView_.classList.add(
- 'display-options-displays-view-mirroring');
// The displays should be centered.
var offsetX =
@@ -766,6 +826,37 @@ cr.define('options', function() {
},
/**
+ * Creates a div element representing the specified display.
+ * @param {Object} display The display object.
+ * @param {boolean} focused True if it's focused.
+ * @private
+ */
+ createDisplayRectangle_: function(display, focused) {
+ var div = document.createElement('div');
+ display.div = div;
+ div.className = 'displays-display';
+ if (focused)
+ div.classList.add('displays-focused');
+
+ // div needs to be added to the DOM tree first, otherwise offsetHeight for
+ // nameContainer below cannot be computed.
+ this.displaysView_.appendChild(div);
+
+ var nameContainer = document.createElement('div');
+ nameContainer.textContent = display.name;
+ div.appendChild(nameContainer);
+ div.style.width = Math.floor(display.width * this.visualScale_) + 'px';
+ var newHeight = Math.floor(display.height * this.visualScale_);
+ div.style.height = newHeight + 'px';
+ nameContainer.style.marginTop =
+ (newHeight - nameContainer.offsetHeight) / 2 + 'px';
+
+ div.onmousedown = this.onMouseDown_.bind(this);
+ div.ontouchstart = this.onTouchStart_.bind(this);
+ return div;
+ },
+
+ /**
* Layouts the display rectangles according to the current layout_.
* @private
*/
@@ -773,8 +864,18 @@ cr.define('options', function() {
var maxWidth = 0;
var maxHeight = 0;
var boundingBox = {left: 0, right: 0, top: 0, bottom: 0};
+ this.primaryDisplay_ = null;
+ this.secondaryDisplay_ = null;
+ var focusedDisplay = null;
for (var i = 0; i < this.displays_.length; i++) {
var display = this.displays_[i];
+ if (display.isPrimary)
+ this.primaryDisplay_ = display;
+ else
+ this.secondaryDisplay_ = display;
+ if (i == this.focusedIndex_)
+ focusedDisplay = display;
+
boundingBox.left = Math.min(boundingBox.left, display.x);
boundingBox.right = Math.max(
boundingBox.right, display.x + display.width);
@@ -784,6 +885,8 @@ cr.define('options', function() {
maxWidth = Math.max(maxWidth, display.width);
maxHeight = Math.max(maxHeight, display.height);
}
+ if (!this.primaryDisplay_)
+ return;
// Make the margin around the bounding box.
var areaWidth = boundingBox.right - boundingBox.left + maxWidth;
@@ -798,13 +901,6 @@ cr.define('options', function() {
this.displaysView_.style.height =
Math.ceil(areaHeight * this.visualScale_) + 'px';
- var boundingCenter = {
- x: Math.floor((boundingBox.right + boundingBox.left) *
- this.visualScale_ / 2),
- y: Math.floor((boundingBox.bottom + boundingBox.top) *
- this.visualScale_ / 2)
- };
-
// Centering the bounding box of the display rectangles.
var offset = {
x: Math.floor(this.displaysView_.offsetWidth / 2 -
@@ -813,59 +909,70 @@ cr.define('options', function() {
(boundingBox.bottom + boundingBox.top) * this.visualScale_ / 2)
};
- for (var i = 0; i < this.displays_.length; i++) {
- var display = this.displays_[i];
- var div = document.createElement('div');
- display.div = div;
-
- div.className = 'displays-display';
- if (i == this.focusedIndex_)
- div.classList.add('displays-focused');
-
- if (display.isPrimary) {
- this.primaryDisplay_ = display;
- } else {
- this.secondaryDisplay_ = display;
+ // Layouting the display rectangles. First layout the primaryDisplay and
+ // then layout the secondary which is attaching to the primary.
+ var primaryDiv = this.createDisplayRectangle_(
+ this.primaryDisplay_, this.primaryDisplay_ == focusedDisplay);
+ primaryDiv.style.left =
+ Math.floor(this.primaryDisplay_.x * this.visualScale_) +
+ offset.x + 'px';
+ primaryDiv.style.top =
+ Math.floor(this.primaryDisplay_.y * this.visualScale_) +
+ offset.y + 'px';
+ this.primaryDisplay_.originalPosition = {
+ x: primaryDiv.offsetLeft, y: primaryDiv.offsetTop};
+
+ if (this.secondaryDisplay_) {
+ var secondaryDiv = this.createDisplayRectangle_(
+ this.secondaryDisplay_, this.secondaryDisplay_ == focusedDisplay);
+ // Don't trust the secondary display's x or y, because it may cause a
+ // 1px gap due to rounding, which will create a fake update on end
+ // dragging. See crbug.com/386401
+ switch (this.layout_) {
+ case options.SecondaryDisplayLayout.TOP:
+ secondaryDiv.style.left =
+ Math.floor(this.secondaryDisplay_.x * this.visualScale_) +
+ offset.x + 'px';
+ secondaryDiv.style.top =
+ primaryDiv.offsetTop - secondaryDiv.offsetHeight + 'px';
+ break;
+ case options.SecondaryDisplayLayout.RIGHT:
+ secondaryDiv.style.left =
+ primaryDiv.offsetLeft + primaryDiv.offsetWidth + 'px';
+ secondaryDiv.style.top =
+ Math.floor(this.secondaryDisplay_.y * this.visualScale_) +
+ offset.y + 'px';
+ break;
+ case options.SecondaryDisplayLayout.BOTTOM:
+ secondaryDiv.style.left =
+ Math.floor(this.secondaryDisplay_.x * this.visualScale_) +
+ offset.x + 'px';
+ secondaryDiv.style.top =
+ primaryDiv.offsetTop + primaryDiv.offsetHeight + 'px';
+ break;
+ case options.SecondaryDisplayLayout.LEFT:
+ secondaryDiv.style.left =
+ primaryDiv.offsetLeft - secondaryDiv.offsetWidth + 'px';
+ secondaryDiv.style.top =
+ Math.floor(this.secondaryDisplay_.y * this.visualScale_) +
+ offset.y + 'px';
+ break;
}
- var displayNameContainer = document.createElement('div');
- displayNameContainer.textContent = display.name;
- div.appendChild(displayNameContainer);
- display.nameContainer = displayNameContainer;
- display.div.style.width =
- Math.floor(display.width * this.visualScale_) + 'px';
- var newHeight = Math.floor(display.height * this.visualScale_);
- display.div.style.height = newHeight + 'px';
- div.style.left =
- Math.floor(display.x * this.visualScale_) + offset.x + 'px';
- div.style.top =
- Math.floor(display.y * this.visualScale_) + offset.y + 'px';
- display.nameContainer.style.marginTop =
- (newHeight - display.nameContainer.offsetHeight) / 2 + 'px';
-
- div.onmousedown = this.onMouseDown_.bind(this);
- div.ontouchstart = this.onTouchStart_.bind(this);
-
- this.displaysView_.appendChild(div);
-
- // Set the margin top to place the display name at the middle of the
- // rectangle. Note that this has to be done after it's added into the
- // |displaysView_|. Otherwise its offsetHeight is yet 0.
- displayNameContainer.style.marginTop =
- (div.offsetHeight - displayNameContainer.offsetHeight) / 2 + 'px';
- display.originalPosition = {x: div.offsetLeft, y: div.offsetTop};
+ this.secondaryDisplay_.originalPosition = {
+ x: secondaryDiv.offsetLeft, y: secondaryDiv.offsetTop};
}
},
/**
* Called when the display arrangement has changed.
- * @param {boolean} mirroring Whether current mode is mirroring or not.
- * @param {Array.<options.DisplayInfo>} displays The list of the display
+ * @param {options.MultiDisplayMode} multi display mode.
+ * @param {Array<options.DisplayInfo>} displays The list of the display
* information.
* @param {options.SecondaryDisplayLayout} layout The layout strategy.
* @param {number} offset The offset of the secondary display.
* @private
*/
- onDisplayChanged_: function(mirroring, displays, layout, offset) {
+ onDisplayChanged_: function(mode, displays, layout, offset) {
if (!this.visible)
return;
@@ -879,20 +986,25 @@ cr.define('options', function() {
this.layout_ = layout;
+ var mirroring = mode == options.MultiDisplayMode.MIRRORING;
+ var unifiedDesktopEnabled = mode == options.MultiDisplayMode.UNIFIED;
+
$('display-options-toggle-mirroring').textContent =
loadTimeData.getString(
mirroring ? 'stopMirroring' : 'startMirroring');
// Focus to the first display next to the primary one when |displays| list
// is updated.
- if (mirroring) {
+ if (mirroring || unifiedDesktopEnabled) {
this.focusedIndex_ = null;
} else if (this.mirroring_ != mirroring ||
+ this.unifiedDesktopEnabled_ != unifiedDesktopEnabled ||
this.displays_.length != displays.length) {
this.focusedIndex_ = 0;
}
this.mirroring_ = mirroring;
+ this.unifiedDesktopEnabled_ = unifiedDesktopEnabled;
this.displays_ = displays;
this.resetDisplaysView_();
@@ -901,14 +1013,28 @@ cr.define('options', function() {
else
this.layoutDisplays_();
+ $('display-options-unified-desktop').hidden =
+ !this.showUnifiedDesktopOption_;
+
+ $('display-options-toggle-unified-desktop').checked =
+ this.unifiedDesktopEnabled_;
+
+ var disableUnifiedDesktopOption =
+ (this.mirroring_ ||
+ (!this.unifiedDesktopEnabled_ &&
+ this.displays_.length == 1));
+
+ $('display-options-toggle-unified-desktop').disabled =
+ disableUnifiedDesktopOption;
+
this.updateSelectedDisplayDescription_();
}
};
DisplayOptions.setDisplayInfo = function(
- mirroring, displays, layout, offset) {
+ mode, displays, layout, offset) {
DisplayOptions.getInstance().onDisplayChanged_(
- mirroring, displays, layout, offset);
+ mode, displays, layout, offset);
};
// Export
diff --git a/chromium/chrome/browser/resources/options/chromeos/display_overscan.css b/chromium/chrome/browser/resources/options/chromeos/display_overscan.css
index 3a09e408e12..6069a806044 100644
--- a/chromium/chrome/browser/resources/options/chromeos/display_overscan.css
+++ b/chromium/chrome/browser/resources/options/chromeos/display_overscan.css
@@ -28,8 +28,8 @@
#display-overscan-operation-arrows {
background-image: -webkit-image-set(
- url('overscan_arrows.png') 1x,
- url('overscan_arrows_2x.png') 2x);
+ url(overscan_arrows.png) 1x,
+ url(overscan_arrows_2x.png) 2x);
background-position: center;
background-repeat: no-repeat;
height: 51px;
@@ -38,8 +38,8 @@
#display-overscan-operation-shift {
background-image: -webkit-image-set(
- url('overscan_shift.png') 1x,
- url('overscan_shift_2x.png') 2x);
+ url(overscan_shift.png) 1x,
+ url(overscan_shift_2x.png) 2x);
background-position: center;
background-repeat: no-repeat;
height: 23px;
@@ -48,8 +48,8 @@
html[dir=rtl] #display-overscan-operation-shift {
background-image: -webkit-image-set(
- url('overscan_shift_rtl.png') 1x,
- url('overscan_shift_rtl_2x.png') 2x);
+ url(overscan_shift_rtl.png) 1x,
+ url(overscan_shift_rtl_2x.png) 2x);
}
#display-overscan-button-strip {
diff --git a/chromium/chrome/browser/resources/options/chromeos/internet_detail.css b/chromium/chrome/browser/resources/options/chromeos/internet_detail.css
index a027a56259f..1528bc08781 100644
--- a/chromium/chrome/browser/resources/options/chromeos/internet_detail.css
+++ b/chromium/chrome/browser/resources/options/chromeos/internet_detail.css
@@ -53,6 +53,14 @@
padding: 4px;
}
+#vpn-tab.third-party-vpn-provider tr.built-in-vpn-provider-only {
+ display: none;
+}
+
+#vpn-tab:not(.third-party-vpn-provider) tr.third-party-vpn-provider-only {
+ display: none;
+}
+
#ip-config-list {
min-height: 96px !important;
}
diff --git a/chromium/chrome/browser/resources/options/chromeos/internet_detail.html b/chromium/chrome/browser/resources/options/chromeos/internet_detail.html
index 788c41ae149..09e25672699 100644
--- a/chromium/chrome/browser/resources/options/chromeos/internet_detail.html
+++ b/chromium/chrome/browser/resources/options/chromeos/internet_detail.html
@@ -73,7 +73,8 @@
<span>
<span i18n-content="inetPreferredNetwork"></span>
<span class="controlled-setting-indicator"
- managed="Priority"></span>
+ managed="Priority"
+ internet-detail-for="prefer-network-wifi"></span>
</span>
</label>
</div>
@@ -87,7 +88,9 @@
<span>
<span i18n-content="inetAutoConnectNetwork"></span>
<span class="controlled-setting-indicator"
- managed="WiFi.AutoConnect"></span>
+ managed="WiFi.AutoConnect"
+ internet-detail-for="auto-connect-network-wifi">
+ </span>
</span>
</label>
</div>
@@ -157,7 +160,9 @@
<span>
<span i18n-content="inetAutoConnectNetwork"></span>
<span class="controlled-setting-indicator"
- managed="WiMAX.AutoConnect"></span>
+ managed="WiMAX.AutoConnect"
+ internet-detail-for="auto-connect-network-wimax">
+ </span>
</span>
</label>
</div>
@@ -198,7 +203,7 @@
<div id="vpn-tab" class="subpages-tab-contents vpn-details">
<section>
<table class="option-control-table">
- <tr class="auto-connect-network">
+ <tr class="auto-connect-network built-in-vpn-provider-only">
<td>
<div class="checkbox controlled-setting-with-label">
<label>
@@ -206,7 +211,8 @@
<span>
<span i18n-content="inetAutoConnectNetwork"></span>
<span class="controlled-setting-indicator"
- managed="VPN.AutoConnect"></span>
+ managed="VPN.AutoConnect"
+ internet-detail-for="auto-connect-network-vpn"></span>
</span>
</label>
</div>
@@ -216,19 +222,24 @@
<td class="option-name" i18n-content="inetServiceName"></td>
<td id="inet-service-name" class="option-value"></td>
</tr>
- <tr>
+ <tr class="built-in-vpn-provider-only">
<td class="option-name" i18n-content="inetServerHostname"></td>
<td>
<input class="option-value" id="inet-server-hostname"></input>
<span class="controlled-setting-indicator"
- managed="VPN.Host"></span>
+ managed="VPN.Host"
+ internet-detail-for="inet-server-hostname"></span>
</td>
</tr>
<tr>
<td class="option-name" i18n-content="inetProviderType"></td>
<td id="inet-provider-type" class="option-value"></td>
</tr>
- <tr>
+ <tr class="third-party-vpn-provider-only">
+ <td class="option-name" i18n-content="inetProviderName"></td>
+ <td id="inet-provider-name" class="option-value"></td>
+ </tr>
+ <tr class="built-in-vpn-provider-only">
<td class="option-name" i18n-content="inetUsername"></td>
<td id="inet-username" class="option-value"></td>
</tr>
@@ -283,7 +294,8 @@
</option>
</select>
<span class="controlled-setting-indicator"
- managed="Cellular.APN"></span>
+ managed="Cellular.APN"
+ internet-detail-for="select-apn"></span>
</td>
</tr>
<tr class="gsm-only apn-details-view">
@@ -323,7 +335,9 @@
<span>
<span i18n-content="inetAutoConnectNetwork"></span>
<span class="controlled-setting-indicator"
- managed="Cellular.AutoConnect"></span>
+ managed="Cellular.AutoConnect"
+ internet-detail-for="auto-connect-network-cellular">
+ </span>
</span>
</label>
</div>
@@ -409,7 +423,7 @@
<span>
<span i18n-content="ipAutomaticConfiguration"></span>
<span class="controlled-setting-indicator"
- managed="StaticIPConfig.IPAddress"></span>
+ managed="IPAddressConfigType"></span>
</span>
</label>
</div>
@@ -438,7 +452,11 @@
<label>
<input id="automatic-dns-radio" type="radio" name="dnstype"
value="automatic">
- <span i18n-content="automaticNameServers"></span>
+ <span>
+ <span i18n-content="automaticNameServers"></span>
+ <span class="controlled-setting-indicator"
+ managed="NameServersConfigType"></span>
+ </span>
</label>
</div>
<div id="automatic-dns-display" class="dns-display"></div>
@@ -497,7 +515,8 @@
<span>
<span i18n-content="lockSimCard"></span>
<span class="controlled-setting-indicator"
- managed="Cellular.SIMLockStatus.LockEnabled"></span>
+ managed="Cellular.SIMLockStatus.LockEnabled"
+ internet-detail-for="sim-card-lock-enabled"></span>
</span>
</label>
</div>
@@ -506,7 +525,8 @@
<div id="change-pin-area">
<button id="change-pin" i18n-content="changePinButton"></button>
<span class="controlled-setting-indicator"
- managed="Cellular.SIMLockStatus.LockType"></span>
+ managed="Cellular.SIMLockStatus.LockType"
+ internet-detail-for="change-pin"></span>
</div>
</section>
</div>
diff --git a/chromium/chrome/browser/resources/options/chromeos/internet_detail.js b/chromium/chrome/browser/resources/options/chromeos/internet_detail.js
index 3fdc203184e..fa636df9ad9 100644
--- a/chromium/chrome/browser/resources/options/chromeos/internet_detail.js
+++ b/chromium/chrome/browser/resources/options/chromeos/internet_detail.js
@@ -7,27 +7,19 @@
// NOTE(stevenjb): This code is in the process of being converted to be
// compatible with the networkingPrivate extension API:
// * The network property dictionaries are being converted to use ONC values.
-// * chrome.send calls will be replaced with an API object that simulates the
-// networkingPrivate API. See network_config.js.
+// * chrome.send calls will be replaced with chrome.networkingPrivate calls.
// See crbug.com/279351 for more info.
-/** @typedef {{address: (string|undefined),
- * gateway: (string|undefined),
- * nameServers: (string|undefined),
- * netmask: (string|undefined),
- * prefixLength: (number|undefined)}}
- * @see chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
- */
-var IPInfo;
-
cr.define('options.internet', function() {
var OncData = cr.onc.OncData;
var Page = cr.ui.pageManager.Page;
var PageManager = cr.ui.pageManager.PageManager;
/** @const */ var IPAddressField = options.internet.IPAddressField;
- /** @const */ var GoogleNameServersString = '8.8.4.4,8.8.8.8';
+ /** @const */ var GoogleNameServers = ['8.8.4.4', '8.8.8.8'];
/** @const */ var CarrierGenericUMTS = 'Generic UMTS';
+ /** @const */ var CarrierSprint = 'Sprint';
+ /** @const */ var CarrierVerizon = 'Verizon Wireless';
/**
* Helper function to set hidden attribute for elements matching a selector.
@@ -88,22 +80,6 @@ cr.define('options.internet', function() {
}
/**
- * Sends the 'checked' state of a control to chrome for a network.
- * @param {string} path The service path of the network.
- * @param {string} message The message to send to chrome.
- * @param {string} checkboxId The id of the checkbox with the value to send.
- * @param {string=} opt_action Optional action to record.
- */
- function sendCheckedIfEnabled(path, message, checkboxId, opt_action) {
- var checkbox = assertInstanceof($(checkboxId), HTMLInputElement);
- if (!checkbox.hidden && !checkbox.disabled) {
- chrome.send(message, [path, !!checkbox.checked]);
- if (opt_action)
- sendChromeMetricsAction(opt_action);
- }
- }
-
- /**
* Send metrics to Chrome when the detailed page is opened.
* @param {string} type The ONC type of the network being shown.
* @param {string} state The ONC network state.
@@ -152,6 +128,78 @@ cr.define('options.internet', function() {
return netmask;
}
+ /**
+ * Returns the prefix length from the netmask string.
+ * @param {string} netmask The netmask string, e.g. 255.255.255.0.
+ * @return {number} The corresponding netmask or -1 if invalid.
+ */
+ function netmaskToPrefixLength(netmask) {
+ var prefixLength = 0;
+ var tokens = netmask.split('.');
+ if (tokens.length != 4)
+ return -1;
+ for (var i = 0; i < tokens.length; ++i) {
+ var token = tokens[i];
+ // If we already found the last mask and the current one is not
+ // '0' then the netmask is invalid. For example, 255.224.255.0
+ if (prefixLength / 8 != i) {
+ if (token != '0')
+ return -1;
+ } else if (token == '255') {
+ prefixLength += 8;
+ } else if (token == '254') {
+ prefixLength += 7;
+ } else if (token == '252') {
+ prefixLength += 6;
+ } else if (token == '248') {
+ prefixLength += 5;
+ } else if (token == '240') {
+ prefixLength += 4;
+ } else if (token == '224') {
+ prefixLength += 3;
+ } else if (token == '192') {
+ prefixLength += 2;
+ } else if (token == '128') {
+ prefixLength += 1;
+ } else if (token == '0') {
+ prefixLength += 0;
+ } else {
+ // mask is not a valid number.
+ return -1;
+ }
+ }
+ return prefixLength;
+ }
+
+ // Returns true if we should show the 'View Account' button for |onc|.
+ // TODO(stevenjb): We should query the Mobile Config API for whether or not to
+ // show the 'View Account' button once it is integrated with Settings.
+ function shouldShowViewAccountButton(onc) {
+ var activationState = onc.getActiveValue('Cellular.ActivationState');
+ if (activationState != 'Activating' && activationState != 'Activated')
+ return false;
+
+ // If no online payment URL was provided by Shill, only show 'View Account'
+ // for Verizon Wireless.
+ if (!onc.getActiveValue('Cellular.PaymentPortal.Url') &&
+ onc.getActiveValue('Cellular.Carrier') != CarrierVerizon) {
+ return false;
+ }
+
+ // 'View Account' should only be shown for connected networks, or
+ // disconnected LTE networks with a valid MDN.
+ var connectionState = onc.getActiveValue('ConnectionState');
+ if (connectionState != 'Connected') {
+ var technology = onc.getActiveValue('Cellular.NetworkTechnology');
+ if (technology != 'LTE' && technology != 'LTEAdvanced')
+ return false;
+ if (!onc.getActiveValue('Cellular.MDN'))
+ return false;
+ }
+
+ return true;
+ }
+
/////////////////////////////////////////////////////////////////////////////
// DetailsInternetPage class:
@@ -161,10 +209,16 @@ cr.define('options.internet', function() {
* @extends {cr.ui.pageManager.Page}
*/
function DetailsInternetPage() {
- // Cached Apn properties
+ // If non-negative, indicates a custom entry in select-apn.
this.userApnIndex_ = -1;
- this.selectedApnIndex_ = -1;
+
+ // The custom APN properties associated with entry |userApnIndex_|.
this.userApn_ = {};
+
+ // The currently selected APN entry in $('select-apn') (which may or may not
+ // == userApnIndex_).
+ this.selectedApnIndex_ = -1;
+
// We show the Proxy configuration tab for remembered networks and when
// configuring a proxy from the login screen.
this.showProxy_ = false;
@@ -181,20 +235,40 @@ cr.define('options.internet', function() {
initializePage: function() {
Page.prototype.initializePage.call(this);
this.initializePageContents_();
+
+ chrome.networkingPrivate.onNetworksChanged.addListener(
+ this.onNetworksChanged_.bind(this));
+
this.showNetworkDetails_();
},
/**
- * Auto-activates the network details dialog if network information
+ * Automatically shows the network details dialog if network information
* is included in the URL.
*/
showNetworkDetails_: function() {
- var servicePath = parseQueryParams(window.location).servicePath;
- if (!servicePath || !servicePath.length)
+ var guid = parseQueryParams(window.location).guid;
+ if (!guid || !guid.length)
+ return;
+ chrome.send('loadVPNProviders');
+ chrome.networkingPrivate.getManagedProperties(
+ guid, DetailsInternetPage.initializeDetailsPage);
+ },
+
+ /**
+ * networkingPrivate callback when networks change.
+ * @param {Array<string>} changes List of GUIDs whose properties have
+ * changed.
+ * @private
+ */
+ onNetworksChanged_: function(changes) {
+ if (!this.onc_)
return;
- // TODO(stevenjb): chrome.networkingPrivate.getManagedProperties
- // with initializeDetailsPage as the callback.
- chrome.send('getManagedProperties', [servicePath]);
+ var guid = this.onc_.guid();
+ if (changes.indexOf(guid) != -1) {
+ chrome.networkingPrivate.getManagedProperties(
+ guid, DetailsInternetPage.updateConnectionData);
+ }
},
/**
@@ -228,7 +302,7 @@ cr.define('options.internet', function() {
$('view-account-details').addEventListener('click', function(event) {
chrome.send('showMorePlanInfo',
- [DetailsInternetPage.getInstance().servicePath_]);
+ [DetailsInternetPage.getInstance().onc_.guid()]);
PageManager.closeOverlay();
});
@@ -370,33 +444,51 @@ cr.define('options.internet', function() {
},
/**
- * Sends the IP Config info to chrome.
+ * Gets the IPConfig ONC Object.
* @param {string} nameServerType The selected name server type:
* 'automatic', 'google', or 'user'.
+ * @return {Object} The IPConfig ONC object.
* @private
*/
- sendIpConfig_: function(nameServerType) {
- var userNameServerString = '';
- if (nameServerType == 'user') {
+ getIpConfig_: function(nameServerType) {
+ var ipConfig = {};
+ // If 'ip-address' is empty, automatic configuration will be used.
+ if (!$('ip-automatic-configuration-checkbox').checked &&
+ $('ip-address').model.value) {
+ ipConfig['IPAddress'] = $('ip-address').model.value;
+ var netmask = $('ip-netmask').model.value;
+ var routingPrefix = 0;
+ if (netmask) {
+ routingPrefix = netmaskToPrefixLength(netmask);
+ if (routingPrefix == -1) {
+ console.error('Invalid netmask: ' + netmask);
+ routingPrefix = 0;
+ }
+ }
+ ipConfig['RoutingPrefix'] = routingPrefix;
+ ipConfig['Gateway'] = $('ip-gateway').model.value || '';
+ }
+
+ // Note: If no nameserver fields are set, automatic configuration will be
+ // used. TODO(stevenjb): Validate input fields.
+ if (nameServerType != 'automatic') {
var userNameServers = [];
- for (var i = 1; i <= 4; ++i) {
- var nameServerField = $('ipconfig-dns' + i);
- // Skip empty values.
- if (nameServerField && nameServerField.model &&
- nameServerField.model.value) {
- userNameServers.push(nameServerField.model.value);
+ if (nameServerType == 'google') {
+ userNameServers = GoogleNameServers.slice();
+ } else if (nameServerType == 'user') {
+ for (var i = 1; i <= 4; ++i) {
+ var nameServerField = $('ipconfig-dns' + i);
+ // Skip empty values.
+ if (nameServerField && nameServerField.model &&
+ nameServerField.model.value) {
+ userNameServers.push(nameServerField.model.value);
+ }
}
}
- userNameServerString = userNameServers.sort().join(',');
+ if (userNameServers.length)
+ ipConfig['NameServers'] = userNameServers.sort();
}
- chrome.send('setIPConfig',
- [this.servicePath_,
- Boolean($('ip-automatic-configuration-checkbox').checked),
- $('ip-address').model.value || '',
- $('ip-netmask').model.value || '',
- $('ip-gateway').model.value || '',
- nameServerType,
- userNameServerString]);
+ return ipConfig;
},
/**
@@ -645,27 +737,33 @@ cr.define('options.internet', function() {
return;
}
+ var connectable = onc.getActiveValue('Connectable');
var connectState = onc.getActiveValue('ConnectionState');
if (connectState == 'NotConnected') {
+ $('details-internet-disconnect').hidden = true;
$('details-internet-login').hidden = false;
// Connecting to an unconfigured network might trigger certificate
// installation UI. Until that gets handled here, always enable the
- // Connect button.
- $('details-internet-login').disabled = false;
- $('details-internet-disconnect').hidden = true;
+ // Connect button for built-in networks.
+ var enabled = (this.type_ != 'VPN') ||
+ (onc.getActiveValue('VPN.Type') != 'ThirdPartyVPN') ||
+ connectable;
+ $('details-internet-login').disabled = !enabled;
} else {
$('details-internet-login').hidden = true;
$('details-internet-disconnect').hidden = false;
}
- var connectable = onc.getActiveValue('Connectable');
- if (connectState != 'Connected' &&
- (!connectable || onc.getWiFiSecurity() != 'None' ||
- (this.type_ == 'WiMAX' || this.type_ == 'VPN'))) {
- $('details-internet-configure').hidden = false;
- } else {
- $('details-internet-configure').hidden = true;
+ var showConfigure = false;
+ if (this.type_ == 'VPN') {
+ showConfigure = true;
+ } else if (this.type_ == 'WiMAX' && connectState == 'NotConnected') {
+ showConfigure = true;
+ } else if (this.type_ == 'WiFi') {
+ showConfigure = (connectState == 'NotConnected' &&
+ (!connectable || onc.getWiFiSecurity() != 'None'));
}
+ $('details-internet-configure').hidden = !showConfigure;
},
/**
@@ -695,10 +793,10 @@ cr.define('options.internet', function() {
$('sim-card-lock-enabled').checked = lockEnabled;
$('change-pin').hidden = !lockEnabled;
}
- showViewAccount = onc.getActiveValue('showViewAccountButton');
+ showViewAccount = shouldShowViewAccountButton(onc);
var activationState = onc.getActiveValue('Cellular.ActivationState');
- showActivate = activationState == 'NotActivated' ||
- activationState == 'PartiallyActivated';
+ showActivate = (activationState == 'NotActivated' ||
+ activationState == 'PartiallyActivated');
}
$('view-account-details').hidden = !showViewAccount;
@@ -716,8 +814,9 @@ cr.define('options.internet', function() {
populateHeader_: function() {
var onc = this.onc_;
- $('network-details-title').textContent = onc.getTranslatedValue('Name');
- var connectionState = onc.getActiveValue('ConnectionState');
+ $('network-details-title').textContent =
+ this.networkTitle_ || onc.getTranslatedValue('Name');
+
var connectionStateString = onc.getTranslatedValue('ConnectionState');
$('network-details-subtitle-status').textContent = connectionStateString;
@@ -748,18 +847,29 @@ cr.define('options.internet', function() {
},
/**
- * Helper method called from initializeDetailsPage to initialize the Apn
- * list.
+ * Helper method to insert a 'user' option into the Apn list.
+ * @param {Object} userOption The 'user' apn dictionary
* @private
*/
- initializeApnList_: function() {
- var onc = this.onc_;
+ insertApnUserOption_: function(userOption) {
+ // Add the 'user' option before the last option ('other')
+ var apnSelector = $('select-apn');
+ assert(apnSelector.length > 0);
+ var otherOption = apnSelector[apnSelector.length - 1];
+ apnSelector.add(userOption, otherOption);
+ this.userApnIndex_ = apnSelector.length - 2;
+ this.selectedApnIndex_ = this.userApnIndex_;
+ },
+ /**
+ * Helper method called from initializeApnList to populate the Apn list.
+ * @param {Array} apnList List of available APNs.
+ * @private
+ */
+ populateApnList_: function(apnList) {
+ var onc = this.onc_;
var apnSelector = $('select-apn');
- // Clear APN lists, keep only last element that "other".
- while (apnSelector.length != 1) {
- apnSelector.remove(0);
- }
+ assert(apnSelector.length == 1);
var otherOption = apnSelector[0];
var activeApn = onc.getActiveValue('Cellular.APN.AccessPointName');
var activeUsername = onc.getActiveValue('Cellular.APN.Username');
@@ -770,7 +880,6 @@ cr.define('options.internet', function() {
onc.getActiveValue('Cellular.LastGoodAPN.Username');
var lastGoodPassword =
onc.getActiveValue('Cellular.LastGoodAPN.Password');
- var apnList = onc.getActiveValue('Cellular.APNList');
for (var i = 0; i < apnList.length; i++) {
var apnDict = apnList[i];
var option = document.createElement('option');
@@ -780,30 +889,58 @@ cr.define('options.internet', function() {
option.textContent =
name ? (name + ' (' + accessPointName + ')') : accessPointName;
option.value = i;
- // Insert new option before "other" option.
+ // Insert new option before 'other' option.
apnSelector.add(option, otherOption);
if (this.selectedApnIndex_ != -1)
continue;
- // If this matches the active Apn, or LastGoodApn (or there is no last
- // good APN), set it as the selected Apn.
- if ((activeApn == accessPointName &&
- activeUsername == apnDict['Username'] &&
- activePassword == apnDict['Password']) ||
- (!activeApn && !lastGoodApn) ||
- (!activeApn &&
- lastGoodApn == accessPointName &&
- lastGoodUsername == apnDict['Username'] &&
- lastGoodPassword == apnDict['Password'])) {
+ // If this matches the active Apn name, or LastGoodApn name (or there
+ // is no last good APN), set it as the selected Apn.
+ if ((activeApn == accessPointName) ||
+ (!activeApn && (!lastGoodApn || lastGoodApn == accessPointName))) {
this.selectedApnIndex_ = i;
}
}
if (this.selectedApnIndex_ == -1 && activeApn) {
- var activeOption = document.createElement('option');
- activeOption.textContent = activeApn;
- activeOption.value = -1;
- apnSelector.add(activeOption, otherOption);
- this.selectedApnIndex_ = apnSelector.length - 2;
- this.userApnIndex_ = this.selectedApnIndex_;
+ this.userApn_ = activeApn;
+ // Create a 'user' entry for any active apn not in the list.
+ var userOption = document.createElement('option');
+ userOption.textContent = activeApn;
+ userOption.value = -1;
+ this.insertApnUserOption_(userOption);
+ }
+ },
+
+ /**
+ * Helper method called from initializeDetailsPage to initialize the Apn
+ * list.
+ * @private
+ */
+ initializeApnList_: function() {
+ this.selectedApnIndex_ = -1;
+ this.userApnIndex_ = -1;
+
+ var onc = this.onc_;
+ var apnSelector = $('select-apn');
+
+ // Clear APN lists, keep only last element, 'other'.
+ while (apnSelector.length != 1)
+ apnSelector.remove(0);
+
+ var apnList = onc.getActiveValue('Cellular.APNList');
+ if (apnList) {
+ // Populate the list with the existing APNs.
+ this.populateApnList_(apnList);
+ } else {
+ // Create a single 'default' entry.
+ var otherOption = apnSelector[0];
+ var defaultOption = document.createElement('option');
+ defaultOption.textContent =
+ loadTimeData.getString('cellularApnUseDefault');
+ defaultOption.value = -1;
+ // Add 'default' entry before 'other' option
+ apnSelector.add(defaultOption, otherOption);
+ assert(apnSelector.length == 2); // 'default', 'other'
+ this.selectedApnIndex_ = 0; // Select 'default'
}
assert(this.selectedApnIndex_ >= 0);
apnSelector.selectedIndex = this.selectedApnIndex_;
@@ -812,37 +949,49 @@ cr.define('options.internet', function() {
},
/**
+ * Helper function for setting APN properties.
+ * @param {Object} apnValue Dictionary of APN properties.
+ * @private
+ */
+ setActiveApn_: function(apnValue) {
+ var activeApn = {};
+ var apnName = apnValue['AccessPointName'];
+ if (apnName) {
+ activeApn['AccessPointName'] = apnName;
+ activeApn['Username'] = stringFromValue(apnValue['Username']);
+ activeApn['Password'] = stringFromValue(apnValue['Password']);
+ }
+ // Set the cached ONC data.
+ this.onc_.setProperty('Cellular.APN', activeApn);
+ // Set an ONC object with just the APN values.
+ var oncData = new OncData({});
+ oncData.setProperty('Cellular.APN', activeApn);
+ chrome.networkingPrivate.setProperties(this.onc_.guid(),
+ oncData.getData());
+ },
+
+ /**
* Event Listener for the cellular-apn-use-default button.
* @private
*/
setDefaultApn_: function() {
- var onc = this.onc_;
var apnSelector = $('select-apn');
+ // Remove the 'user' entry if it exists.
if (this.userApnIndex_ != -1) {
+ assert(this.userApnIndex_ < apnSelector.length - 1);
apnSelector.remove(this.userApnIndex_);
this.userApnIndex_ = -1;
}
- var iApn = -1;
- var apnList = onc.getActiveValue('Cellular.APNList');
- if (apnList != undefined && apnList.length > 0) {
- iApn = 0;
- var defaultApn = apnList[iApn];
- var activeApn = {};
- activeApn['AccessPointName'] =
- stringFromValue(defaultApn['AccessPointName']);
- activeApn['Username'] = stringFromValue(defaultApn['Username']);
- activeApn['Password'] = stringFromValue(defaultApn['Password']);
- onc.setManagedProperty('Cellular.APN', activeApn);
- chrome.send('setApn', [this.servicePath_,
- activeApn['AccessPointName'],
- activeApn['Username'],
- activeApn['Password']]);
- }
+ var apnList = this.onc_.getActiveValue('Cellular.APNList');
+ var iApn = (apnList != undefined && apnList.length > 0) ? 0 : -1;
apnSelector.selectedIndex = iApn;
this.selectedApnIndex_ = iApn;
+ // Clear any user APN entry to inform Chrome to use the default APN.
+ this.setActiveApn_({});
+
updateHidden('.apn-list-view', false);
updateHidden('.apn-details-view', true);
},
@@ -855,32 +1004,29 @@ cr.define('options.internet', function() {
if (apnValue == '')
return;
- var onc = this.onc_;
var apnSelector = $('select-apn');
var activeApn = {};
activeApn['AccessPointName'] = stringFromValue(apnValue);
activeApn['Username'] = stringFromValue($('cellular-apn-username').value);
activeApn['Password'] = stringFromValue($('cellular-apn-password').value);
- onc.setManagedProperty('Cellular.APN', activeApn);
+ this.setActiveApn_(activeApn);
+ // Set the user selected APN.
this.userApn_ = activeApn;
- chrome.send('setApn', [this.servicePath_,
- activeApn['AccessPointName'],
- activeApn['Username'],
- activeApn['Password']]);
+ // Remove any existing 'user' entry.
if (this.userApnIndex_ != -1) {
+ assert(this.userApnIndex_ < apnSelector.length - 1);
apnSelector.remove(this.userApnIndex_);
this.userApnIndex_ = -1;
}
+ // Create a new 'user' entry with the new active apn.
var option = document.createElement('option');
option.textContent = activeApn['AccessPointName'];
option.value = -1;
option.selected = true;
- apnSelector.add(option, apnSelector[apnSelector.length - 1]);
- this.userApnIndex_ = apnSelector.length - 2;
- this.selectedApnIndex_ = this.userApnIndex_;
+ this.insertApnUserOption_(option);
updateHidden('.apn-list-view', false);
updateHidden('.apn-details-view', true);
@@ -890,11 +1036,7 @@ cr.define('options.internet', function() {
* Event Listener for the cellular-apn-cancel button.
* @private
*/
- cancelApn_: function() {
- $('select-apn').selectedIndex = this.selectedApnIndex_;
- updateHidden('.apn-list-view', false);
- updateHidden('.apn-details-view', true);
- },
+ cancelApn_: function() { this.initializeApnList_(); },
/**
* Event Listener for the select-apn button.
@@ -903,31 +1045,31 @@ cr.define('options.internet', function() {
selectApn_: function() {
var onc = this.onc_;
var apnSelector = $('select-apn');
- var apnDict;
if (apnSelector[apnSelector.selectedIndex].value != -1) {
var apnList = onc.getActiveValue('Cellular.APNList');
var apnIndex = apnSelector.selectedIndex;
assert(apnIndex < apnList.length);
- apnDict = apnList[apnIndex];
- chrome.send('setApn', [this.servicePath_,
- stringFromValue(apnDict['AccessPointName']),
- stringFromValue(apnDict['Username']),
- stringFromValue(apnDict['Password'])]);
this.selectedApnIndex_ = apnIndex;
+ this.setActiveApn_(apnList[apnIndex]);
} else if (apnSelector.selectedIndex == this.userApnIndex_) {
- apnDict = this.userApn_;
- chrome.send('setApn', [this.servicePath_,
- stringFromValue(apnDict['AccessPointName']),
- stringFromValue(apnDict['Username']),
- stringFromValue(apnDict['Password'])]);
this.selectedApnIndex_ = apnSelector.selectedIndex;
- } else {
- $('cellular-apn').value =
- stringFromValue(onc.getActiveValue('Cellular.APN.AccessPointName'));
- $('cellular-apn-username').value =
- stringFromValue(onc.getActiveValue('Cellular.APN.Username'));
- $('cellular-apn-password').value =
- stringFromValue(onc.getActiveValue('Cellular.APN.Password'));
+ this.setActiveApn_(this.userApn_);
+ } else { // 'Other'
+ var apnDict;
+ if (this.userApn_['AccessPointName']) {
+ // Fill in the details fields with the existing 'user' config.
+ apnDict = this.userApn_;
+ } else {
+ // No 'user' config, use the current values.
+ apnDict = {};
+ apnDict['AccessPointName'] =
+ onc.getActiveValue('Cellular.APN.AccessPointName');
+ apnDict['Username'] = onc.getActiveValue('Cellular.APN.Username');
+ apnDict['Password'] = onc.getActiveValue('Cellular.APN.Password');
+ }
+ $('cellular-apn').value = stringFromValue(apnDict['AccessPointName']);
+ $('cellular-apn-username').value = stringFromValue(apnDict['Username']);
+ $('cellular-apn-password').value = stringFromValue(apnDict['Password']);
updateHidden('.apn-list-view', true);
updateHidden('.apn-details-view', false);
}
@@ -956,6 +1098,8 @@ cr.define('options.internet', function() {
* Shows a spinner while the carrier is changed.
*/
DetailsInternetPage.showCarrierChangeSpinner = function(visible) {
+ if (!DetailsInternetPage.getInstance().visible)
+ return;
$('switch-carrier-spinner').hidden = !visible;
// Disable any buttons that allow us to operate on cellular networks.
DetailsInternetPage.changeCellularButtonsState(visible);
@@ -968,8 +1112,37 @@ cr.define('options.internet', function() {
var carrierSelector = $('select-carrier');
var carrier = carrierSelector[carrierSelector.selectedIndex].textContent;
DetailsInternetPage.showCarrierChangeSpinner(true);
- chrome.send('setCarrier', [
- DetailsInternetPage.getInstance().servicePath_, carrier]);
+ var guid = DetailsInternetPage.getInstance().onc_.guid();
+ var oncData = new OncData({});
+ oncData.setProperty('Cellular.Carrier', carrier);
+ chrome.networkingPrivate.setProperties(guid, oncData.getData(), function() {
+ // Start activation or show the activation UI after changing carriers.
+ DetailsInternetPage.activateCellular(guid);
+ });
+ };
+
+ /**
+ * If the network is not already activated, starts the activation process or
+ * shows the activation UI. Otherwise does nothing.
+ */
+ DetailsInternetPage.activateCellular = function(guid) {
+ chrome.networkingPrivate.getProperties(guid, function(properties) {
+ var oncData = new OncData(properties);
+ if (oncData.getActiveValue('Cellular.ActivationState') == 'Activated') {
+ DetailsInternetPage.showCarrierChangeSpinner(false);
+ return;
+ }
+ var carrier = oncData.getActiveValue('Cellular.Carrier');
+ if (carrier == CarrierSprint) {
+ // Sprint is directly ativated, call startActivate().
+ chrome.networkingPrivate.startActivate(guid, '', function() {
+ DetailsInternetPage.showCarrierChangeSpinner(false);
+ });
+ } else {
+ DetailsInternetPage.showCarrierChangeSpinner(false);
+ chrome.send('showMorePlanInfo', [guid]);
+ }
+ });
};
/**
@@ -1038,19 +1211,65 @@ cr.define('options.internet', function() {
}
};
- DetailsInternetPage.updateCarrier = function() {
- DetailsInternetPage.showCarrierChangeSpinner(false);
+ DetailsInternetPage.loginFromDetails = function() {
+ DetailsInternetPage.configureOrConnect();
+ PageManager.closeOverlay();
};
- DetailsInternetPage.loginFromDetails = function() {
+ /**
+ * This function identifies unconfigured networks and networks that are
+ * likely to fail (e.g. due to a bad passphrase on a previous connect
+ * attempt). For such networks a configure dialog will be opened. Otherwise
+ * a connection will be attempted.
+ */
+ DetailsInternetPage.configureOrConnect = function() {
var detailsPage = DetailsInternetPage.getInstance();
if (detailsPage.type_ == 'WiFi')
sendChromeMetricsAction('Options_NetworkConnectToWifi');
else if (detailsPage.type_ == 'VPN')
sendChromeMetricsAction('Options_NetworkConnectToVPN');
- // TODO(stevenjb): chrome.networkingPrivate.disableNetworkType
- chrome.send('startConnect', [detailsPage.servicePath_]);
- PageManager.closeOverlay();
+
+ var onc = detailsPage.onc_;
+ var guid = onc.guid();
+ var type = onc.getActiveValue('Type');
+
+ // Built-in VPNs do not correctly set 'Connectable', so we always show the
+ // configuration UI.
+ if (type == 'VPN') {
+ if (onc.getActiveValue('VPN.Type') != 'ThirdPartyVPN') {
+ chrome.send('configureNetwork', [guid]);
+ return;
+ }
+ }
+
+ // If 'Connectable' is false for WiFi or WiMAX, Shill requires
+ // additional configuration to connect, so show the configuration UI.
+ if ((type == 'WiFi' || type == 'WiMAX') &&
+ !onc.getActiveValue('Connectable')) {
+ chrome.send('configureNetwork', [guid]);
+ return;
+ }
+
+ // Secure WiFi networks with ErrorState set most likely require
+ // configuration (e.g. a correct passphrase) before connecting.
+ if (type == 'WiFi' && onc.getWiFiSecurity() != 'None') {
+ var errorState = onc.getActiveValue('ErrorState');
+ if (errorState && errorState != 'Unknown') {
+ chrome.send('configureNetwork', [guid]);
+ return;
+ }
+ }
+
+ // Cellular networks need to be activated before they can be connected to.
+ if (type == 'Cellular') {
+ var activationState = onc.getActiveValue('Cellular.ActivationState');
+ if (activationState != 'Activated' && activationState != 'Unknown') {
+ DetailsInternetPage.activateCellular(guid);
+ return;
+ }
+ }
+
+ chrome.networkingPrivate.startConnect(guid);
};
DetailsInternetPage.disconnectNetwork = function() {
@@ -1059,22 +1278,20 @@ cr.define('options.internet', function() {
sendChromeMetricsAction('Options_NetworkDisconnectWifi');
else if (detailsPage.type_ == 'VPN')
sendChromeMetricsAction('Options_NetworkDisconnectVPN');
- // TODO(stevenjb): chrome.networkingPrivate.startDisconnect
- chrome.send('startDisconnect', [detailsPage.servicePath_]);
+ chrome.networkingPrivate.startDisconnect(detailsPage.onc_.guid());
PageManager.closeOverlay();
};
DetailsInternetPage.configureNetwork = function() {
var detailsPage = DetailsInternetPage.getInstance();
- chrome.send('configureNetwork', [detailsPage.servicePath_]);
+ chrome.send('configureNetwork', [detailsPage.onc_.guid()]);
PageManager.closeOverlay();
};
DetailsInternetPage.activateFromDetails = function() {
var detailsPage = DetailsInternetPage.getInstance();
- if (detailsPage.type_ == 'Cellular') {
- chrome.send('activateNetwork', [detailsPage.servicePath_]);
- }
+ if (detailsPage.type_ == 'Cellular')
+ DetailsInternetPage.activateCellular(detailsPage.onc_.guid());
PageManager.closeOverlay();
};
@@ -1085,33 +1302,38 @@ cr.define('options.internet', function() {
DetailsInternetPage.setDetails = function() {
var detailsPage = DetailsInternetPage.getInstance();
var type = detailsPage.type_;
- var servicePath = detailsPage.servicePath_;
+ var oncData = new OncData({});
+ var autoConnectCheckboxId = '';
if (type == 'WiFi') {
- sendCheckedIfEnabled(servicePath,
- 'setPreferNetwork',
- 'prefer-network-wifi',
- 'Options_NetworkSetPrefer');
- sendCheckedIfEnabled(servicePath,
- 'setAutoConnect',
- 'auto-connect-network-wifi',
- 'Options_NetworkAutoConnect');
+ var preferredCheckbox =
+ assertInstanceof($('prefer-network-wifi'), HTMLInputElement);
+ if (!preferredCheckbox.hidden && !preferredCheckbox.disabled) {
+ var kPreferredPriority = 1;
+ var priority = preferredCheckbox.checked ? kPreferredPriority : 0;
+ oncData.setProperty('Priority', priority);
+ sendChromeMetricsAction('Options_NetworkSetPrefer');
+ }
+ autoConnectCheckboxId = 'auto-connect-network-wifi';
} else if (type == 'WiMAX') {
- sendCheckedIfEnabled(servicePath,
- 'setAutoConnect',
- 'auto-connect-network-wimax',
- 'Options_NetworkAutoConnect');
+ autoConnectCheckboxId = 'auto-connect-network-wimax';
} else if (type == 'Cellular') {
- sendCheckedIfEnabled(servicePath,
- 'setAutoConnect',
- 'auto-connect-network-cellular',
- 'Options_NetworkAutoConnect');
+ autoConnectCheckboxId = 'auto-connect-network-cellular';
} else if (type == 'VPN') {
- chrome.send('setServerHostname',
- [servicePath, $('inet-server-hostname').value]);
- sendCheckedIfEnabled(servicePath,
- 'setAutoConnect',
- 'auto-connect-network-vpn',
- 'Options_NetworkAutoConnect');
+ var providerType = detailsPage.onc_.getActiveValue('VPN.Type');
+ if (providerType != 'ThirdPartyVPN') {
+ oncData.setProperty('VPN.Type', providerType);
+ oncData.setProperty('VPN.Host', $('inet-server-hostname').value);
+ autoConnectCheckboxId = 'auto-connect-network-vpn';
+ }
+ }
+ if (autoConnectCheckboxId != '') {
+ var autoConnectCheckbox =
+ assertInstanceof($(autoConnectCheckboxId), HTMLInputElement);
+ if (!autoConnectCheckbox.hidden && !autoConnectCheckbox.disabled) {
+ var autoConnectKey = type + '.AutoConnect';
+ oncData.setProperty(autoConnectKey, !!autoConnectCheckbox.checked);
+ sendChromeMetricsAction('Options_NetworkAutoConnect');
+ }
}
var nameServerTypes = ['automatic', 'google', 'user'];
@@ -1122,7 +1344,18 @@ cr.define('options.internet', function() {
break;
}
}
- detailsPage.sendIpConfig_(nameServerType);
+ var ipConfig = detailsPage.getIpConfig_(nameServerType);
+ var ipAddressType = ('IPAddress' in ipConfig) ? 'Static' : 'DHCP';
+ var nameServersType = ('NameServers' in ipConfig) ? 'Static' : 'DHCP';
+ oncData.setProperty('IPAddressConfigType', ipAddressType);
+ oncData.setProperty('NameServersConfigType', nameServersType);
+ oncData.setProperty('StaticIPConfig', ipConfig);
+
+ var data = oncData.getData();
+ if (Object.keys(data).length > 0) {
+ // TODO(stevenjb): Only set changed properties.
+ chrome.networkingPrivate.setProperties(detailsPage.onc_.guid(), data);
+ }
PageManager.closeOverlay();
};
@@ -1174,7 +1407,7 @@ cr.define('options.internet', function() {
if (!detailsPage.visible)
return;
- if (oncData.servicePath != detailsPage.servicePath_)
+ if (oncData.GUID != detailsPage.onc_.guid())
return;
// Update our cached data object.
@@ -1186,17 +1419,6 @@ cr.define('options.internet', function() {
};
/**
- * Method called from Chrome in response to getManagedProperties.
- * We only use this when we want to call initializeDetailsPage.
- * TODO(stevenjb): Eliminate when we switch to networkingPrivate
- * (initializeDetailsPage will be provided as the callback).
- * @param {Object} oncData Dictionary of ONC properties.
- */
- DetailsInternetPage.getManagedPropertiesResult = function(oncData) {
- DetailsInternetPage.initializeDetailsPage(oncData);
- };
-
- /**
* Initializes the details page with the provided ONC data.
* @param {Object} oncData Dictionary of ONC properties.
*/
@@ -1204,13 +1426,22 @@ cr.define('options.internet', function() {
var onc = new OncData(oncData);
var detailsPage = DetailsInternetPage.getInstance();
- detailsPage.servicePath_ = oncData.servicePath;
detailsPage.onc_ = onc;
var type = onc.getActiveValue('Type');
detailsPage.type_ = type;
sendShowDetailsMetrics(type, onc.getActiveValue('ConnectionState'));
+ if (type == 'VPN') {
+ // Cache the dialog title, which will contain the provider name in the
+ // case of a third-party VPN provider. This caching is important as the
+ // provider may go away while the details dialog is being shown, causing
+ // subsequent updates to be unable to determine the correct title.
+ detailsPage.networkTitle_ = options.VPNProviders.formatNetworkName(onc);
+ } else {
+ delete detailsPage.networkTitle_;
+ }
+
detailsPage.populateHeader_();
detailsPage.updateConnectionButtonVisibilty_();
detailsPage.updateDetails_();
@@ -1223,7 +1454,7 @@ cr.define('options.internet', function() {
if (remembered) {
detailsPage.showProxy_ = true;
// Inform Chrome which network to use for proxy configuration.
- chrome.send('selectNetwork', [detailsPage.servicePath_]);
+ chrome.send('selectNetwork', [detailsPage.onc_.guid()]);
} else {
detailsPage.showProxy_ = false;
}
@@ -1234,6 +1465,10 @@ cr.define('options.internet', function() {
var restrictedString = loadTimeData.getString(
restricted ? 'restrictedYes' : 'restrictedNo');
+ // These objects contain an 'automatic' property that is displayed when
+ // ip-automatic-configuration-checkbox is checked, and a 'value' property
+ // that is displayed when unchecked and used to set the associated ONC
+ // property for StaticIPConfig on commit.
var inetAddress = {};
var inetNetmask = {};
var inetGateway = {};
@@ -1272,13 +1507,14 @@ cr.define('options.internet', function() {
}
}
- // Override the "automatic" values with the real saved DHCP values,
- // if they are set.
+ // Override the 'automatic' properties with the saved DHCP values if the
+ // saved value is set, and set any unset 'value' properties.
var savedNameServersString;
var savedIpAddress = onc.getActiveValue('SavedIPConfig.IPAddress');
if (savedIpAddress != undefined) {
inetAddress.automatic = savedIpAddress;
- inetAddress.value = savedIpAddress;
+ if (!inetAddress.value)
+ inetAddress.value = savedIpAddress;
}
var savedPrefix = onc.getActiveValue('SavedIPConfig.RoutingPrefix');
if (savedPrefix != undefined) {
@@ -1286,13 +1522,16 @@ cr.define('options.internet', function() {
var savedNetmask = prefixLengthToNetmask(
/** @type {number} */(savedPrefix));
inetNetmask.automatic = savedNetmask;
- inetNetmask.value = savedNetmask;
+ if (!inetNetmask.value)
+ inetNetmask.value = savedNetmask;
}
var savedGateway = onc.getActiveValue('SavedIPConfig.Gateway');
if (savedGateway != undefined) {
inetGateway.automatic = savedGateway;
- inetGateway.value = savedGateway;
+ if (!inetGateway.value)
+ inetGateway.value = savedGateway;
}
+
var savedNameServers = onc.getActiveValue('SavedIPConfig.NameServers');
if (savedNameServers) {
savedNameServers = savedNameServers.sort();
@@ -1300,29 +1539,28 @@ cr.define('options.internet', function() {
}
var ipAutoConfig = 'automatic';
-
- var staticNameServersString;
- var staticIpAddress = onc.getActiveValue('StaticIPConfig.IPAddress');
- if (staticIpAddress != undefined) {
+ if (onc.getActiveValue('IPAddressConfigType') == 'Static') {
ipAutoConfig = 'user';
+ var staticIpAddress = onc.getActiveValue('StaticIPConfig.IPAddress');
inetAddress.user = staticIpAddress;
inetAddress.value = staticIpAddress;
- }
- var staticPrefix = onc.getActiveValue('StaticIPConfig.RoutingPrefix');
- if (staticPrefix != undefined) {
- assert(typeof staticPrefix == 'number');
+
+ var staticPrefix = onc.getActiveValue('StaticIPConfig.RoutingPrefix');
+ if (typeof staticPrefix != 'number')
+ staticPrefix = 0;
var staticNetmask = prefixLengthToNetmask(
- /** @type {number} */(staticPrefix));
+ /** @type {number} */ (staticPrefix));
inetNetmask.user = staticNetmask;
inetNetmask.value = staticNetmask;
- }
- var staticGateway = onc.getActiveValue('StaticIPConfig.Gateway');
- if (staticGateway != undefined) {
+
+ var staticGateway = onc.getActiveValue('StaticIPConfig.Gateway');
inetGateway.user = staticGateway;
inetGateway.value = staticGateway;
}
- var staticNameServers = onc.getActiveValue('StaticIPConfig.NameServers');
- if (staticNameServers) {
+
+ var staticNameServersString;
+ if (onc.getActiveValue('NameServersConfigType') == 'Static') {
+ var staticNameServers = onc.getActiveValue('StaticIPConfig.NameServers');
staticNameServers = staticNameServers.sort();
staticNameServersString = staticNameServers.join(',');
}
@@ -1343,21 +1581,26 @@ cr.define('options.internet', function() {
configureAddressField($('ip-netmask'), inetNetmask);
configureAddressField($('ip-gateway'), inetGateway);
- // Set Nameserver fields.
+ // Set Nameserver fields. Nameservers are 'automatic' by default. If a
+ // static namerserver is set, use that unless it does not match a non
+ // empty 'NameServers' value (indicating that the custom nameservers are
+ // invalid or not being applied for some reason). TODO(stevenjb): Only
+ // set these properites if they change so that invalid custom values do
+ // not get lost.
var nameServerType = 'automatic';
- if (staticNameServersString) {
- // If static nameservers are defined and match the google name servers,
- // show that in the UI, otherwise show the custom static nameservers.
- if (staticNameServersString == GoogleNameServersString)
+ if (staticNameServersString &&
+ (!inetNameServersString ||
+ staticNameServersString == inetNameServersString)) {
+ if (staticNameServersString == GoogleNameServers.join(','))
nameServerType = 'google';
- else if (staticNameServersString == inetNameServersString)
+ else
nameServerType = 'user';
}
if (nameServerType == 'automatic')
$('automatic-dns-display').textContent = inetNameServersString;
else
$('automatic-dns-display').textContent = savedNameServersString;
- $('google-dns-display').textContent = GoogleNameServersString;
+ $('google-dns-display').textContent = GoogleNameServers.join(',');
var nameServersUser = [];
if (staticNameServers) {
@@ -1476,13 +1719,13 @@ cr.define('options.internet', function() {
if (currentCarrierIndex == -1)
$('service-name').textContent = networkName;
+ // TODO(stevenjb): Ideally many of these should be localized.
$('network-technology').textContent =
onc.getActiveValue('Cellular.NetworkTechnology');
$('roaming-state').textContent =
onc.getTranslatedValue('Cellular.RoamingState');
$('cellular-restricted-connectivity').textContent = restrictedString;
- // 'errorMessage' is a non ONC property added by Chrome.
- $('error-state').textContent = onc.getActiveValue('errorMessage');
+ $('error-state').textContent = onc.getActiveValue('ErrorState');
$('manufacturer').textContent =
onc.getActiveValue('Cellular.Manufacturer');
$('model-id').textContent = onc.getActiveValue('Cellular.ModelID');
@@ -1527,33 +1770,50 @@ cr.define('options.internet', function() {
$('auto-connect-network-cellular').disabled = false;
} else if (type == 'VPN') {
OptionsPage.showTab($('vpn-nav-tab'));
+ var providerType = onc.getActiveValue('VPN.Type');
+ var isThirdPartyVPN = providerType == 'ThirdPartyVPN';
+ $('vpn-tab').classList.toggle('third-party-vpn-provider',
+ isThirdPartyVPN);
+
$('inet-service-name').textContent = networkName;
$('inet-provider-type').textContent =
onc.getTranslatedValue('VPN.Type');
- var providerType = onc.getActiveValue('VPN.Type');
- var usernameKey;
- if (providerType == 'OpenVPN')
- usernameKey = 'VPN.OpenVPN.Username';
- else if (providerType == 'L2TP-IPsec')
- usernameKey = 'VPN.L2TP.Username';
-
- if (usernameKey) {
- $('inet-username').parentElement.hidden = false;
- $('inet-username').textContent = onc.getActiveValue(usernameKey);
+
+ if (isThirdPartyVPN) {
+ $('inet-provider-name').textContent = '';
+ var extensionID = onc.getActiveValue('VPN.ThirdPartyVPN.ExtensionID');
+ var providers = options.VPNProviders.getProviders();
+ for (var i = 0; i < providers.length; ++i) {
+ if (extensionID == providers[i].extensionID) {
+ $('inet-provider-name').textContent = providers[i].name;
+ break;
+ }
+ }
} else {
- $('inet-username').parentElement.hidden = true;
+ var usernameKey;
+ if (providerType == 'OpenVPN')
+ usernameKey = 'VPN.OpenVPN.Username';
+ else if (providerType == 'L2TP-IPsec')
+ usernameKey = 'VPN.L2TP.Username';
+
+ if (usernameKey) {
+ $('inet-username').parentElement.hidden = false;
+ $('inet-username').textContent = onc.getActiveValue(usernameKey);
+ } else {
+ $('inet-username').parentElement.hidden = true;
+ }
+ var inetServerHostname = $('inet-server-hostname');
+ inetServerHostname.value = onc.getActiveValue('VPN.Host');
+ inetServerHostname.resetHandler = function() {
+ PageManager.hideBubble();
+ var recommended = onc.getRecommendedValue('VPN.Host');
+ if (recommended != undefined)
+ inetServerHostname.value = recommended;
+ };
+ $('auto-connect-network-vpn').checked =
+ onc.getActiveValue('VPN.AutoConnect');
+ $('auto-connect-network-vpn').disabled = false;
}
- var inetServerHostname = $('inet-server-hostname');
- inetServerHostname.value = onc.getActiveValue('VPN.Host');
- inetServerHostname.resetHandler = function() {
- PageManager.hideBubble();
- var recommended = onc.getRecommendedValue('VPN.Host');
- if (recommended != undefined)
- inetServerHostname.value = recommended;
- };
- $('auto-connect-network-vpn').checked =
- onc.getActiveValue('VPN.AutoConnect');
- $('auto-connect-network-vpn').disabled = false;
} else {
OptionsPage.showTab($('internet-nav-tab'));
}
@@ -1582,7 +1842,7 @@ cr.define('options.internet', function() {
/** @type {{value: *, controlledBy: *, recommendedValue: *}} */(
propValue));
indicators[i].handlePrefChange(event);
- var forElement = $(indicators[i].getAttribute('for'));
+ var forElement = $(indicators[i].getAttribute('internet-detail-for'));
if (forElement) {
if (event.value.controlledBy == 'policy')
forElement.disabled = true;
diff --git a/chromium/chrome/browser/resources/options/chromeos/keyboard_overlay.js b/chromium/chrome/browser/resources/options/chromeos/keyboard_overlay.js
index ae4baa03efe..b18af10166e 100644
--- a/chromium/chrome/browser/resources/options/chromeos/keyboard_overlay.js
+++ b/chromium/chrome/browser/resources/options/chromeos/keyboard_overlay.js
@@ -8,7 +8,7 @@ cr.define('options', function() {
* Auto-repeat delays (in ms) for the corresponding slider values, from
* long to short. The values were chosen to provide a large range while giving
* several options near the defaults.
- * @type {!Array.<number>}
+ * @type {!Array<number>}
* @const
*/
var AUTO_REPEAT_DELAYS =
@@ -18,7 +18,7 @@ cr.define('options', function() {
* Auto-repeat intervals (in ms) for the corresponding slider values, from
* long to short. The slider itself is labeled "rate", the inverse of
* interval, and goes from slow (long interval) to fast (short interval).
- * @type {!Array.<number>}
+ * @type {!Array<number>}
* @const
*/
var AUTO_REPEAT_INTERVALS =
@@ -138,7 +138,7 @@ cr.define('options', function() {
* |value|.
* @param {string} id The slider's ID.
* @param {number} value The value to find.
- * @param {!Array.<number>} values The array to search.
+ * @param {!Array<number>} values The array to search.
* @private
*/
updateSliderFromValue_: function(id, value, values) {
diff --git a/chromium/chrome/browser/resources/options/chromeos/network_list.js b/chromium/chrome/browser/resources/options/chromeos/network_list.js
index 4c65b342717..bcd947ad165 100644
--- a/chromium/chrome/browser/resources/options/chromeos/network_list.js
+++ b/chromium/chrome/browser/resources/options/chromeos/network_list.js
@@ -3,15 +3,23 @@
// found in the LICENSE file.
/**
+ * Partial definition of the result of networkingPrivate.getProperties()).
* @typedef {{
* ConnectionState: string,
- * iconURL: string,
- * policyManaged: boolean,
- * servicePath: string
+ * Cellular: {
+ * Family: ?string,
+ * SIMPresent: ?boolean,
+ * SIMLockStatus: { LockType: ?string },
+ * SupportNetworkScan: ?boolean
+ * },
+ * GUID: string,
+ * Name: string,
+ * Source: string,
+ * Type: string
* }}
- * @see chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
+ * @see extensions/common/api/networking_private.idl
*/
-var NetworkInfo;
+var NetworkProperties;
cr.define('options.network', function() {
var ArrayDataModel = cr.ui.ArrayDataModel;
@@ -28,12 +36,19 @@ cr.define('options.network', function() {
*/
function Constants() {}
- // Cellular activation states:
- Constants.ACTIVATION_STATE_UNKNOWN = 0;
- Constants.ACTIVATION_STATE_ACTIVATED = 1;
- Constants.ACTIVATION_STATE_ACTIVATING = 2;
- Constants.ACTIVATION_STATE_NOT_ACTIVATED = 3;
- Constants.ACTIVATION_STATE_PARTIALLY_ACTIVATED = 4;
+ /**
+ * Valid network type names.
+ */
+ Constants.NETWORK_TYPES = ['Ethernet', 'WiFi', 'WiMAX', 'Cellular', 'VPN'];
+
+ /**
+ * Helper function to check whether |type| is a valid network type.
+ * @param {string} type A string that may contain a valid network type.
+ * @return {boolean} Whether the string represents a valid network type.
+ */
+ function isNetworkType(type) {
+ return (Constants.NETWORK_TYPES.indexOf(type) != -1);
+ }
/**
* Order in which controls are to appear in the network list sorted by key.
@@ -53,53 +68,39 @@ cr.define('options.network', function() {
var activeMenu_ = null;
/**
- * Indicates if cellular networks are available.
- * @type {boolean}
+ * The state of the cellular device or undefined if not available.
+ * @type {string|undefined}
* @private
*/
- var cellularAvailable_ = false;
+ var cellularDeviceState_ = undefined;
/**
- * Indicates if cellular networks are enabled.
- * @type {boolean}
+ * The active cellular network or null if none.
+ * @type {?NetworkProperties}
* @private
*/
- var cellularEnabled_ = false;
+ var cellularNetwork_ = null;
/**
- * Indicates if cellular device supports network scanning.
- * @type {boolean}
+ * The active ethernet network or null if none.
+ * @type {?NetworkProperties}
* @private
*/
- var cellularSupportsScan_ = false;
+ var ethernetNetwork_ = null;
/**
- * Indicates the current SIM lock type of the cellular device.
- * @type {string}
+ * The state of the WiFi device or undefined if not available.
+ * @type {string|undefined}
* @private
*/
- var cellularSimLockType_ = '';
+ var wifiDeviceState_ = undefined;
/**
- * Indicates whether the SIM card is absent on the cellular device.
- * @type {boolean}
+ * The state of the WiMAX device or undefined if not available.
+ * @type {string|undefined}
* @private
*/
- var cellularSimAbsent_ = false;
-
- /**
- * Indicates if WiMAX networks are available.
- * @type {boolean}
- * @private
- */
- var wimaxAvailable_ = false;
-
- /**
- * Indicates if WiMAX networks are enabled.
- * @type {boolean}
- * @private
- */
- var wimaxEnabled_ = false;
+ var wimaxDeviceState_ = undefined;
/**
* Indicates if mobile data roaming is enabled.
@@ -109,19 +110,14 @@ cr.define('options.network', function() {
var enableDataRoaming_ = false;
/**
- * Icon to use when not connected to a particular type of network.
- * @type {!Object.<string, string>} Mapping of network type to icon data url.
- * @private
- */
- var defaultIcons_ = {};
-
- /**
* Returns the display name for 'network'.
- * @param {Object} data The network data dictionary.
+ * @param {NetworkProperties} data The network data dictionary.
*/
function getNetworkName(data) {
if (data.Type == 'Ethernet')
return loadTimeData.getString('ethernetName');
+ if (data.Type == 'VPN')
+ return options.VPNProviders.formatNetworkName(new cr.onc.OncData(data));
return data.Name;
}
@@ -149,13 +145,11 @@ cr.define('options.network', function() {
}
/**
- * @param {string} servicePath The network service path.
+ * @param {string} guid The network GUID.
*/
- function showDetails(servicePath) {
- // TODO(stevenjb): chrome.networkingPrivate.getManagedProperties
- // (Note: we will need to provide DetailsInternetPage.initializeDetailsPage
- // as the callback).
- chrome.send('getManagedProperties', [servicePath]);
+ function showDetails(guid) {
+ chrome.networkingPrivate.getManagedProperties(
+ guid, DetailsInternetPage.initializeDetailsPage);
}
/**
@@ -172,7 +166,7 @@ cr.define('options.network', function() {
/**
* Description of the network group or control.
- * @type {Object.<string,Object>}
+ * @type {Object<string,Object>}
* @private
*/
data_: null,
@@ -185,18 +179,11 @@ cr.define('options.network', function() {
subtitle_: null,
/**
- * Icon for the network control.
+ * Div containing the list item icon.
* @type {?Element}
* @private
*/
- icon_: null,
-
- /**
- * Indicates if in the process of connecting to a network.
- * @type {boolean}
- * @private
- */
- connecting_: false,
+ iconDiv_: null,
/**
* Description of the network control.
@@ -217,42 +204,52 @@ cr.define('options.network', function() {
},
/**
- * URL for the network icon.
- * @type {string}
+ * Sets the icon based on a network state object.
+ * @param {!NetworkProperties} data Network state properties.
*/
- set iconURL(iconURL) {
- this.icon_.style.backgroundImage = url(iconURL);
+ set iconData(data) {
+ if (!isNetworkType(data.Type))
+ return;
+ var networkIcon = this.getNetworkIcon();
+ networkIcon.networkState = CrOncDataElement.create(
+ /** @type {chrome.networkingPrivate.NetworkStateProperties} */ (
+ data));
},
/**
- * Type of network icon. Each type corresponds to a CSS rule.
+ * Sets the icon based on a network type or a special type indecator, e.g.
+ * 'add-connection'
* @type {string}
*/
set iconType(type) {
- if (defaultIcons_[type])
- this.iconURL = defaultIcons_[type];
- else
- this.icon_.classList.add('network-' + type.toLowerCase());
- },
-
- /**
- * Indicates if the network is in the process of being connected.
- * @type {boolean}
- */
- set connecting(state) {
- this.connecting_ = state;
- if (state)
- this.icon_.classList.add('network-connecting');
- else
- this.icon_.classList.remove('network-connecting');
+ if (isNetworkType(type)) {
+ var networkIcon = this.getNetworkIcon();
+ networkIcon.networkType = type;
+ } else {
+ // Special cases. e.g. 'add-connection'. Background images are
+ // defined in browser_options.css.
+ var oldIcon = /** @type {CrNetworkIconElement} */ (
+ this.iconDiv_.querySelector('cr-network-icon'));
+ if (oldIcon)
+ this.iconDiv_.removeChild(oldIcon);
+ this.iconDiv_.classList.add('network-' + type.toLowerCase());
+ }
},
/**
- * Indicates if the network is in the process of being connected.
- * @type {boolean}
+ * Returns any existing network icon for the list item or creates a new one.
+ * @return {!CrNetworkIconElement} The network icon for the list item.
*/
- get connecting() {
- return this.connecting_;
+ getNetworkIcon: function() {
+ var networkIcon = /** @type {CrNetworkIconElement} */ (
+ this.iconDiv_.querySelector('cr-network-icon'));
+ if (!networkIcon) {
+ networkIcon = /** @type {!CrNetworkIconElement} */ (
+ document.createElement('cr-network-icon'));
+ networkIcon.isListItem = false;
+ this.iconDiv_.appendChild(networkIcon);
+ }
+ return networkIcon;
},
/**
@@ -281,9 +278,9 @@ cr.define('options.network', function() {
decorate: function() {
ListItem.prototype.decorate.call(this);
this.className = 'network-group';
- this.icon_ = this.ownerDocument.createElement('div');
- this.icon_.className = 'network-icon';
- this.appendChild(this.icon_);
+ this.iconDiv_ = this.ownerDocument.createElement('div');
+ this.iconDiv_.className = 'network-icon';
+ this.appendChild(this.iconDiv_);
var textContent = this.ownerDocument.createElement('div');
textContent.className = 'network-group-labels';
this.appendChild(textContent);
@@ -330,9 +327,9 @@ cr.define('options.network', function() {
this.subtitle = null;
if (this.data.iconType)
this.iconType = this.data.iconType;
- this.addEventListener('click', function() {
+ this.addEventListener('click', (function() {
this.showMenu();
- });
+ }).bind(this));
},
/**
@@ -353,6 +350,7 @@ cr.define('options.network', function() {
menu.className = 'network-menu';
menu.hidden = true;
Menu.decorate(menu);
+ menu.menuItemSelector = '.network-menu-item';
for (var i = 0; i < this.data.menu.length; i++) {
var entry = this.data.menu[i];
createCallback_(menu, null, entry.label, entry.command);
@@ -362,11 +360,29 @@ cr.define('options.network', function() {
return null;
},
+ /**
+ * Determines if a menu can be updated on the fly. Menus that cannot be
+ * updated are fully regenerated using createMenu. The advantage of
+ * updating a menu is that it can preserve ordering of networks avoiding
+ * entries from jumping around after an update.
+ * @return {boolean} Whether the menu can be updated on the fly.
+ */
canUpdateMenu: function() {
return false;
},
/**
+ * Removes the current menu contents, causing it to be regenerated when the
+ * menu is shown the next time. If the menu is showing right now, its
+ * contents are regenerated immediately and the menu remains visible.
+ */
+ refreshMenu: function() {
+ this.menu_ = null;
+ if (activeMenu_ == this.getMenuName())
+ this.showMenu();
+ },
+
+ /**
* Displays a popup menu.
*/
showMenu: function() {
@@ -380,7 +396,7 @@ cr.define('options.network', function() {
rebuild = true;
var existing = $(this.getMenuName());
if (existing) {
- if (this.updateMenu())
+ if (this.canUpdateMenu() && this.updateMenu())
return;
closeMenu_();
}
@@ -404,8 +420,7 @@ cr.define('options.network', function() {
this.menu_.hidden = false;
}
if (rescan) {
- // TODO(stevenjb): chrome.networkingPrivate.requestNetworkScan
- chrome.send('requestNetworkScan');
+ chrome.networkingPrivate.requestNetworkScan();
}
}
};
@@ -413,8 +428,8 @@ cr.define('options.network', function() {
/**
* Creates a control for selecting or configuring a network connection based
* on the type of connection (e.g. wifi versus vpn).
- * @param {{key: string, networkList: Array.<NetworkInfo>}} data Description
- * of the network.
+ * @param {{key: string, networkList: Array<!NetworkProperties>}} data
+ * An object containing the network type (key) and an array of networks.
* @constructor
* @extends {NetworkMenuItem}
*/
@@ -425,42 +440,84 @@ cr.define('options.network', function() {
return el;
}
+ /**
+ * Returns true if |source| is a policy managed source.
+ * @param {string} source The ONC source of a network.
+ * @return {boolean} Whether |source| is a managed source.
+ */
+ function isManaged(source) {
+ return (source == 'DevicePolicy' || source == 'UserPolicy');
+ }
+
+ /**
+ * Returns true if |network| is visible.
+ * @param {!chrome.networkingPrivate.NetworkStateProperties} network The
+ * network state properties.
+ * @return {boolean} Whether |network| is visible.
+ */
+ function networkIsVisible(network) {
+ if (network.Type == 'WiFi')
+ return !!(network.WiFi && (network.WiFi.SignalStrength > 0));
+ if (network.Type == 'WiMAX')
+ return !!(network.WiMAX && (network.WiMAX.SignalStrength > 0));
+ // Other network types are always considered 'visible'.
+ return true;
+ }
+
+ /**
+ * Returns true if |cellular| is a GSM network with no sim present.
+ * @param {?NetworkProperties} cellular The network state properties.
+ * @return {boolean} Whether |network| is missing a SIM card.
+ */
+ function isCellularSimAbsent(cellular) {
+ if (!cellular || !cellular.Cellular)
+ return false;
+ return cellular.Cellular.Family == 'GSM' && !cellular.Cellular.SIMPresent;
+ }
+
+ /**
+ * Returns true if |cellular| has a locked SIM card.
+ * @param {?NetworkProperties} cellular The network state properties.
+ * @return {boolean} Whether |network| has a locked SIM card.
+ */
+ function isCellularSimLocked(cellular) {
+ if (!cellular || !cellular.Cellular)
+ return false;
+ var simLockStatus = cellular.Cellular.SIMLockStatus;
+ return !!(simLockStatus && simLockStatus.LockType);
+ }
+
NetworkSelectorItem.prototype = {
__proto__: NetworkMenuItem.prototype,
/** @override */
decorate: function() {
// TODO(kevers): Generalize method of setting default label.
- var policyManaged = false;
this.subtitle = loadTimeData.getString('OncConnectionStateNotConnected');
var list = this.data_.networkList;
- var candidateURL = null;
+ var candidateData = null;
for (var i = 0; i < list.length; i++) {
var networkDetails = list[i];
if (networkDetails.ConnectionState == 'Connecting' ||
networkDetails.ConnectionState == 'Connected') {
this.subtitle = getNetworkName(networkDetails);
this.setSubtitleDirection('ltr');
- policyManaged = networkDetails.policyManaged;
- candidateURL = networkDetails.iconURL;
+ candidateData = networkDetails;
// Only break when we see a connecting network as it is possible to
// have a connected network and a connecting network at the same
// time.
- if (networkDetails.ConnectionState == 'Connecting') {
- this.connecting = true;
- candidateURL = null;
+ if (networkDetails.ConnectionState == 'Connecting')
break;
- }
}
}
- if (candidateURL)
- this.iconURL = candidateURL;
+ if (candidateData)
+ this.iconData = candidateData;
else
this.iconType = this.data.key;
this.showSelector();
- if (policyManaged)
+ if (candidateData && isManaged(candidateData.Source))
this.showManagedNetworkIndicator();
if (activeMenu_ == this.getMenuName()) {
@@ -484,18 +541,21 @@ cr.define('options.network', function() {
menu.className = 'network-menu';
menu.hidden = true;
Menu.decorate(menu);
+ menu.menuItemSelector = '.network-menu-item';
var addendum = [];
if (this.data_.key == 'WiFi') {
addendum.push({
label: loadTimeData.getString('joinOtherNetwork'),
- command: createAddConnectionCallback_('WiFi'),
+ command: createAddNonVPNConnectionCallback_('WiFi'),
data: {}
});
} else if (this.data_.key == 'Cellular') {
- if (cellularEnabled_ && cellularSupportsScan_) {
+ if (cellularDeviceState_ == 'Enabled' &&
+ cellularNetwork_ && cellularNetwork_.Cellular &&
+ cellularNetwork_.Cellular.SupportNetworkScan) {
addendum.push({
label: loadTimeData.getString('otherCellularNetworks'),
- command: createAddConnectionCallback_('Cellular'),
+ command: createAddNonVPNConnectionCallback_('Cellular'),
addClass: ['other-cellulars'],
data: {}
});
@@ -522,11 +582,7 @@ cr.define('options.network', function() {
}
addendum.push(entry);
} else if (this.data_.key == 'VPN') {
- addendum.push({
- label: loadTimeData.getString('joinOtherNetwork'),
- command: createAddConnectionCallback_('VPN'),
- data: {}
- });
+ addendum = addendum.concat(createAddVPNConnectionEntries_());
}
var list = this.data.rememberedNetworks;
@@ -548,22 +604,21 @@ cr.define('options.network', function() {
list = this.data.networkList;
var empty = !list || list.length == 0;
if (list) {
- var connectedVpnServicePath = '';
+ var connectedVpnGuid = '';
for (var i = 0; i < list.length; i++) {
var data = list[i];
this.createNetworkOptionsCallback_(networkGroup, data);
// For VPN only, append a 'Disconnect' item to the dropdown menu.
- if (!connectedVpnServicePath && data.Type == 'VPN' &&
+ if (!connectedVpnGuid && data.Type == 'VPN' &&
(data.ConnectionState == 'Connected' ||
data.ConnectionState == 'Connecting')) {
- connectedVpnServicePath = data.servicePath;
+ connectedVpnGuid = data.GUID;
}
}
- if (connectedVpnServicePath) {
+ if (connectedVpnGuid) {
var disconnectCallback = function() {
sendChromeMetricsAction('Options_NetworkDisconnectVPN');
- // TODO(stevenjb): chrome.networkingPrivate.startDisconnect
- chrome.send('startDisconnect', [connectedVpnServicePath]);
+ chrome.networkingPrivate.startDisconnect(connectedVpnGuid);
};
// Add separator
addendum.push({});
@@ -580,24 +635,21 @@ cr.define('options.network', function() {
label: loadTimeData.getString('turnOffWifi'),
command: function() {
sendChromeMetricsAction('Options_NetworkWifiToggle');
- // TODO(stevenjb): chrome.networkingPrivate.disableNetworkType
- chrome.send('disableNetworkType', ['WiFi']);
+ chrome.networkingPrivate.disableNetworkType('WiFi');
},
data: {}});
} else if (this.data_.key == 'WiMAX') {
addendum.push({
label: loadTimeData.getString('turnOffWimax'),
command: function() {
- // TODO(stevenjb): chrome.networkingPrivate.disableNetworkType
- chrome.send('disableNetworkType', ['WiMAX']);
+ chrome.networkingPrivate.disableNetworkType('WiMAX');
},
data: {}});
} else if (this.data_.key == 'Cellular') {
addendum.push({
label: loadTimeData.getString('turnOffCellular'),
command: function() {
- // TODO(stevenjb): chrome.networkingPrivate.disableNetworkType
- chrome.send('disableNetworkType', ['Cellular']);
+ chrome.networkingPrivate.disableNetworkType('Cellular');
},
data: {}});
}
@@ -629,12 +681,7 @@ cr.define('options.network', function() {
return menu;
},
- /**
- * Determines if a menu can be updated on the fly. Menus that cannot be
- * updated are fully regenerated using createMenu. The advantage of
- * updating a menu is that it can preserve ordering of networks avoiding
- * entries from jumping around after an update.
- */
+ /** @override */
canUpdateMenu: function() {
return this.data_.key == 'WiFi' && activeMenu_ == this.getMenuName();
},
@@ -645,12 +692,11 @@ cr.define('options.network', function() {
* preferred ordering as determined by the network library. If the
* ordering becomes potentially out of sync, then the updated menu is
* marked for disposal on close. Reopening the menu will force a
- * regeneration, which will in turn fix the ordering.
+ * regeneration, which will in turn fix the ordering. This method must only
+ * be called if canUpdateMenu() returned |true|.
* @return {boolean} True if successfully updated.
*/
updateMenu: function() {
- if (!this.canUpdateMenu())
- return false;
var oldMenu = $(this.getMenuName());
var group = oldMenu.getElementsByClassName('network-menu-group')[0];
if (!group)
@@ -687,7 +733,7 @@ cr.define('options.network', function() {
/**
* Extracts a mapping of network names to menu element and position.
* @param {!Element} menu The menu to process.
- * @return {Object.<string, ?{index: number, button: Element}>}
+ * @return {Object<string, ?{index: number, button: Element}>}
* Network mapping.
* @private
*/
@@ -707,17 +753,15 @@ cr.define('options.network', function() {
/**
* Adds a menu item for showing network details.
* @param {!Element} parent The parent element.
- * @param {Object} data Description of the network.
+ * @param {NetworkProperties} data Description of the network.
* @private
*/
createNetworkOptionsCallback_: function(parent, data) {
- var servicePath = data.servicePath;
var menuItem = createCallback_(parent,
data,
getNetworkName(data),
- showDetails.bind(null, servicePath),
- data.iconURL);
- if (data.policyManaged)
+ showDetails.bind(null, data.GUID));
+ if (isManaged(data.Source))
menuItem.appendChild(new ManagedNetworkIndicator());
if (data.ConnectionState == 'Connected' ||
data.ConnectionState == 'Connecting') {
@@ -753,11 +797,11 @@ cr.define('options.network', function() {
this.subtitle = null;
if (this.data.command)
this.addEventListener('click', this.data.command);
- if (this.data.iconURL)
- this.iconURL = this.data.iconURL;
+ if (this.data.iconData)
+ this.iconData = this.data.iconData;
else if (this.data.iconType)
this.iconType = this.data.iconType;
- if (this.data.policyManaged)
+ if (isManaged(this.data.Source))
this.showManagedNetworkIndicator();
},
};
@@ -765,22 +809,26 @@ cr.define('options.network', function() {
/**
* Adds a command to a menu for modifying network settings.
* @param {!Element} menu Parent menu.
- * @param {Object} data Description of the network.
+ * @param {?NetworkProperties} data Description of the network.
* @param {!string} label Display name for the menu item.
* @param {!Function} command Callback function.
- * @param {string=} opt_iconURL Optional URL to an icon for the menu item.
* @return {!Element} The created menu item.
* @private
*/
- function createCallback_(menu, data, label, command, opt_iconURL) {
+ function createCallback_(menu, data, label, command) {
var button = menu.ownerDocument.createElement('div');
button.className = 'network-menu-item';
- var buttonIcon = menu.ownerDocument.createElement('div');
- buttonIcon.className = 'network-menu-item-icon';
- button.appendChild(buttonIcon);
- if (opt_iconURL)
- buttonIcon.style.backgroundImage = url(opt_iconURL);
+ var buttonIconDiv = menu.ownerDocument.createElement('div');
+ buttonIconDiv.className = 'network-icon';
+ button.appendChild(buttonIconDiv);
+ if (data && isNetworkType(data.Type)) {
+ var networkIcon = /** @type {!CrNetworkIconElement} */ (
+ document.createElement('cr-network-icon'));
+ buttonIconDiv.appendChild(networkIcon);
+ networkIcon.isListItem = true;
+ networkIcon.networkState = CrOncDataElement.create(data);
+ }
var buttonLabel = menu.ownerDocument.createElement('span');
buttonLabel.className = 'network-menu-item-label';
@@ -801,7 +849,7 @@ cr.define('options.network', function() {
}
}
if (callback != null)
- button.addEventListener('click', callback);
+ button.addEventListener('activate', callback);
else
buttonLabel.classList.add('network-disabled-control');
@@ -835,18 +883,7 @@ cr.define('options.network', function() {
// Wi-Fi control is always visible.
this.update({key: 'WiFi', networkList: []});
- var entryAddWifi = {
- label: loadTimeData.getString('addConnectionWifi'),
- command: createAddConnectionCallback_('WiFi')
- };
- var entryAddVPN = {
- label: loadTimeData.getString('addConnectionVPN'),
- command: createAddConnectionCallback_('VPN')
- };
- this.update({key: 'addConnection',
- iconType: 'add-connection',
- menu: [entryAddWifi, entryAddVPN]
- });
+ this.updateAddConnectionMenuEntries_();
var prefs = options.Preferences.getInstance();
prefs.addEventListener('cros.signed.data_roaming_enabled',
@@ -854,6 +891,65 @@ cr.define('options.network', function() {
enableDataRoaming_ = event.value.value;
});
this.endBatchUpdates();
+
+ this.onNetworkListChanged_(); // Trigger an initial network update
+
+ chrome.networkingPrivate.onNetworkListChanged.addListener(
+ this.onNetworkListChanged_.bind(this));
+ chrome.networkingPrivate.onDeviceStateListChanged.addListener(
+ this.onNetworkListChanged_.bind(this));
+
+ chrome.networkingPrivate.requestNetworkScan();
+
+ options.VPNProviders.addObserver(this.onVPNProvidersChanged_.bind(this));
+ },
+
+ /**
+ * networkingPrivate event called when the network list has changed.
+ */
+ onNetworkListChanged_: function() {
+ var networkList = this;
+ chrome.networkingPrivate.getDeviceStates(function(deviceStates) {
+ var filter = { networkType: 'All' };
+ chrome.networkingPrivate.getNetworks(filter, function(networkStates) {
+ networkList.updateNetworkStates(deviceStates, networkStates);
+ });
+ });
+ },
+
+ /**
+ * Called when the list of VPN providers changes. Refreshes the contents of
+ * menus that list VPN providers.
+ * @private
+ */
+ onVPNProvidersChanged_: function() {
+ // Refresh the contents of the VPN menu.
+ var index = this.indexOf('VPN');
+ if (index != undefined)
+ this.getListItemByIndex(index).refreshMenu();
+
+ // Refresh the contents of the "add connection" menu.
+ this.updateAddConnectionMenuEntries_();
+ index = this.indexOf('addConnection');
+ if (index != undefined)
+ this.getListItemByIndex(index).refreshMenu();
+ },
+
+ /**
+ * Updates the entries in the "add connection" menu, based on the VPN
+ * providers currently enabled in the primary user's profile.
+ * @private
+ */
+ updateAddConnectionMenuEntries_: function() {
+ var entries = [{
+ label: loadTimeData.getString('addConnectionWifi'),
+ command: createAddNonVPNConnectionCallback_('WiFi')
+ }];
+ entries = entries.concat(createAddVPNConnectionEntries_());
+ this.update({key: 'addConnection',
+ iconType: 'add-connection',
+ menu: entries
+ });
},
/**
@@ -866,6 +962,35 @@ cr.define('options.network', function() {
closeMenu_();
},
+ /** @override */
+ handleKeyDown: function(e) {
+ if (activeMenu_) {
+ // keyIdentifier does not report 'Esc' correctly
+ if (e.keyCode == 27 /* Esc */) {
+ closeMenu_();
+ return;
+ }
+
+ if ($(activeMenu_).handleKeyDown(e)) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ return;
+ }
+
+ if (e.keyIdentifier == 'Enter' ||
+ e.keyIdentifier == 'U+0020' /* Space */) {
+ var selectedListItem = this.getListItemByIndex(
+ this.selectionModel.selectedIndex);
+ if (selectedListItem) {
+ selectedListItem.click();
+ return;
+ }
+ }
+
+ List.prototype.handleKeyDown.call(this, e);
+ },
+
/**
* Close bubble and menu when a different list item is selected.
* @param {Event} event Event detailing the selection change.
@@ -908,7 +1033,7 @@ cr.define('options.network', function() {
/**
* Updates a network control.
- * @param {Object.<string,string>} data Description of the entry.
+ * @param {Object} data Description of the entry.
*/
update: function(data) {
this.startBatchUpdates();
@@ -956,8 +1081,8 @@ cr.define('options.network', function() {
createItem: function(entry) {
if (entry.networkList)
return new NetworkSelectorItem(
- /** @type {{key: string, networkList: Array.<NetworkInfo>}} */(
- entry));
+ /** @type {{key: string, networkList: Array<!NetworkProperties>}} */
+ (entry));
if (entry.command)
return new NetworkButtonItem(
/** @type {{key: string, subtitle: string, command: Function}} */(
@@ -986,100 +1111,125 @@ cr.define('options.network', function() {
var index = this.indexOf(key);
if (index != undefined) {
var entry = this.dataModel.item(index);
- entry.iconType = active ? 'control-active' :
- 'control-inactive';
+ entry.iconType = active ? 'control-active' : 'control-inactive';
this.update(entry);
}
- }
- };
+ },
- /**
- * Sets the default icon to use for each network type if disconnected.
- * @param {!Object.<string, string>} data Mapping of network type to icon
- * data url.
- */
- NetworkList.setDefaultNetworkIcons = function(data) {
- defaultIcons_ = Object.create(data);
- };
+ /**
+ * Updates the state of network devices and services.
+ * @param {!Array<{State: string, Type: string}>} deviceStates The result
+ * from networkingPrivate.getDeviceStates.
+ * @param {!Array<!chrome.networkingPrivate.NetworkStateProperties>}
+ * networkStates The result from networkingPrivate.getNetworks.
+ */
+ updateNetworkStates: function(deviceStates, networkStates) {
+ // Update device states.
+ cellularDeviceState_ = undefined;
+ wifiDeviceState_ = undefined;
+ wimaxDeviceState_ = undefined;
+ for (var i = 0; i < deviceStates.length; ++i) {
+ var device = deviceStates[i];
+ var type = device.Type;
+ var state = device.State;
+ if (type == 'Cellular')
+ cellularDeviceState_ = cellularDeviceState_ || state;
+ else if (type == 'WiFi')
+ wifiDeviceState_ = wifiDeviceState_ || state;
+ else if (type == 'WiMAX')
+ wimaxDeviceState_ = wimaxDeviceState_ || state;
+ }
- /**
- * Chrome callback for updating network controls.
- * @param {{cellularAvailable: boolean,
- * cellularEnabled: boolean,
- * cellularSimAbsent: boolean,
- * cellularSimLockType: string,
- * cellularSupportsScan: boolean,
- * rememberedList: Array.<NetworkInfo>,
- * vpnList: Array.<NetworkInfo>,
- * wifiAvailable: boolean,
- * wifiEnabled: boolean,
- * wimaxAvailable: boolean,
- * wimaxEnabled: boolean,
- * wiredList: Array.<NetworkInfo>,
- * wirelessList: Array.<NetworkInfo>}} data Description of available
- * network devices and their corresponding state.
- */
- NetworkList.refreshNetworkData = function(data) {
- var networkList = $('network-list');
- networkList.startBatchUpdates();
- cellularAvailable_ = data.cellularAvailable;
- cellularEnabled_ = data.cellularEnabled;
- cellularSupportsScan_ = data.cellularSupportsScan;
- cellularSimAbsent_ = data.cellularSimAbsent;
- cellularSimLockType_ = data.cellularSimLockType;
- wimaxAvailable_ = data.wimaxAvailable;
- wimaxEnabled_ = data.wimaxEnabled;
-
- // Only show Ethernet control if connected.
- var ethernetConnection = getConnection_(data.wiredList);
- if (ethernetConnection) {
- var type = String('Ethernet');
- var path = ethernetConnection.servicePath;
- var ethernetOptions = function() {
- showDetails(path);
- };
- networkList.update(
+ // Update active network states.
+ cellularNetwork_ = null;
+ ethernetNetwork_ = null;
+ for (var i = 0; i < networkStates.length; i++) {
+ // Note: This cast is valid since
+ // networkingPrivate.NetworkStateProperties is a subset of
+ // NetworkProperties and all missing properties are optional.
+ var entry = /** @type {NetworkProperties} */ (networkStates[i]);
+ switch (entry.Type) {
+ case 'Cellular':
+ cellularNetwork_ = cellularNetwork_ || entry;
+ break;
+ case 'Ethernet':
+ ethernetNetwork_ = ethernetNetwork_ || entry;
+ break;
+ }
+ if (cellularNetwork_ && ethernetNetwork_)
+ break;
+ }
+
+ if (cellularNetwork_ && cellularNetwork_.GUID) {
+ // Get the complete set of cellular properties which includes SIM and
+ // Scan properties.
+ var networkList = this;
+ chrome.networkingPrivate.getProperties(
+ cellularNetwork_.GUID, function(cellular) {
+ cellularNetwork_ = /** @type {NetworkProperties} */ (cellular);
+ networkList.updateControls(networkStates);
+ });
+ } else {
+ this.updateControls(networkStates);
+ }
+ },
+
+ /**
+ * Updates network controls.
+ * @param {!Array<!chrome.networkingPrivate.NetworkStateProperties>}
+ * networkStates The result from networkingPrivate.getNetworks.
+ */
+ updateControls: function(networkStates) {
+ this.startBatchUpdates();
+
+ // Only show Ethernet control if connected.
+ if (ethernetNetwork_ && ethernetNetwork_.ConnectionState == 'Connected') {
+ var ethernetOptions = showDetails.bind(null, ethernetNetwork_.GUID);
+ this.update(
{ key: 'Ethernet',
subtitle: loadTimeData.getString('OncConnectionStateConnected'),
- iconURL: ethernetConnection.iconURL,
+ iconData: ethernetNetwork_,
command: ethernetOptions,
- policyManaged: ethernetConnection.policyManaged }
- );
- } else {
- networkList.deleteItem('Ethernet');
- }
-
- if (data.wifiEnabled)
- loadData_('WiFi', data.wirelessList, data.rememberedList);
- else
- addEnableNetworkButton_('WiFi');
+ Source: ethernetNetwork_.Source }
+ );
+ } else {
+ this.deleteItem('Ethernet');
+ }
- // Only show cellular control if available.
- if (data.cellularAvailable) {
- if (data.cellularEnabled)
- loadData_('Cellular', data.wirelessList, data.rememberedList);
+ if (wifiDeviceState_ == 'Enabled')
+ loadData_('WiFi', networkStates);
else
- addEnableNetworkButton_('Cellular');
- } else {
- networkList.deleteItem('Cellular');
- }
+ addEnableNetworkButton_('WiFi');
+
+ // Only show cellular control if available.
+ if (cellularDeviceState_) {
+ if (cellularDeviceState_ == 'Enabled' &&
+ !isCellularSimLocked(cellularNetwork_) &&
+ !isCellularSimAbsent(cellularNetwork_)) {
+ loadData_('Cellular', networkStates);
+ } else {
+ addEnableNetworkButton_('Cellular');
+ }
+ } else {
+ this.deleteItem('Cellular');
+ }
- // Only show wimax control if available. Uses cellular icons.
- if (data.wimaxAvailable) {
- if (data.wimaxEnabled)
- loadData_('WiMAX', data.wirelessList, data.rememberedList);
- else
- addEnableNetworkButton_('WiMAX');
- } else {
- networkList.deleteItem('WiMAX');
- }
+ // Only show wimax control if available. Uses cellular icons.
+ if (wimaxDeviceState_) {
+ if (wimaxDeviceState_ == 'Enabled')
+ loadData_('WiMAX', networkStates);
+ else
+ addEnableNetworkButton_('WiMAX');
+ } else {
+ this.deleteItem('WiMAX');
+ }
- // Only show VPN control if there is at least one VPN configured.
- if (data.vpnList.length > 0)
- loadData_('VPN', data.vpnList, data.rememberedList);
- else
- networkList.deleteItem('VPN');
- networkList.endBatchUpdates();
+ // Only show VPN control if there is at least one VPN configured.
+ if (loadData_('VPN', networkStates) == 0)
+ this.deleteItem('VPN');
+
+ this.endBatchUpdates();
+ }
};
/**
@@ -1089,25 +1239,23 @@ cr.define('options.network', function() {
*/
function addEnableNetworkButton_(type) {
var subtitle = loadTimeData.getString('networkDisabled');
- var icon = (type == 'WiMAX') ? 'Cellular' : type;
var enableNetwork = function() {
if (type == 'WiFi')
sendChromeMetricsAction('Options_NetworkWifiToggle');
if (type == 'Cellular') {
- if (cellularSimLockType_) {
+ if (isCellularSimLocked(cellularNetwork_)) {
chrome.send('simOperation', ['unlock']);
return;
- } else if (cellularEnabled_ && cellularSimAbsent_) {
+ } else if (isCellularSimAbsent(cellularNetwork_)) {
chrome.send('simOperation', ['configure']);
return;
}
}
- // TODO(stevenjb): chrome.networkingPrivate.enableNetworkType
- chrome.send('enableNetworkType', [type]);
+ chrome.networkingPrivate.enableNetworkType(type);
};
$('network-list').update({key: type,
subtitle: subtitle,
- iconType: icon,
+ iconType: type,
command: enableNetwork});
}
@@ -1171,26 +1319,34 @@ cr.define('options.network', function() {
* Updates the list of available networks and their status, filtered by
* network type.
* @param {string} type The type of network.
- * @param {Array} available The list of available networks and their status.
- * @param {Array} remembered The list of remmebered networks.
+ * @param {Array<!chrome.networkingPrivate.NetworkStateProperties>} networks
+ * The list of network objects.
+ * @return {number} The number of visible networks matching |type|.
*/
- function loadData_(type, available, remembered) {
- var data = {key: type};
+ function loadData_(type, networks) {
+ var res = 0;
var availableNetworks = [];
- for (var i = 0; i < available.length; i++) {
- if (available[i].Type == type)
- availableNetworks.push(available[i]);
- }
- data.networkList = availableNetworks;
- if (remembered) {
- var rememberedNetworks = [];
- for (var i = 0; i < remembered.length; i++) {
- if (remembered[i].Type == type)
- rememberedNetworks.push(remembered[i]);
+ var rememberedNetworks = [];
+ for (var i = 0; i < networks.length; i++) {
+ var network = networks[i];
+ if (network.Type != type)
+ continue;
+ if (networkIsVisible(network)) {
+ availableNetworks.push(network);
+ ++res;
+ }
+ if ((type == 'WiFi' || type == 'VPN') && network.Source &&
+ network.Source != 'None') {
+ rememberedNetworks.push(network);
}
- data.rememberedNetworks = rememberedNetworks;
}
+ var data = {
+ key: type,
+ networkList: availableNetworks,
+ rememberedNetworks: rememberedNetworks
+ };
$('network-list').update(data);
+ return res;
}
/**
@@ -1208,40 +1364,63 @@ cr.define('options.network', function() {
}
/**
- * Fetches the active connection.
- * @param {Array.<Object>} networkList List of networks.
- * @return {Object}
+ * Creates a callback function that adds a new connection of the given type.
+ * This method may be used for all network types except VPN.
+ * @param {string} type An ONC network type
+ * @return {function()} The created callback.
* @private
*/
- function getConnection_(networkList) {
- if (!networkList)
- return null;
- for (var i = 0; i < networkList.length; i++) {
- var entry = networkList[i];
- if (entry.ConnectionState == 'Connected' ||
- entry.ConnectionState == 'Connecting')
- return entry;
- }
- return null;
+ function createAddNonVPNConnectionCallback_(type) {
+ return function() {
+ if (type == 'WiFi')
+ sendChromeMetricsAction('Options_NetworkJoinOtherWifi');
+ chrome.send('addNonVPNConnection', [type]);
+ };
}
/**
- * Create a callback function that adds a new connection of the given type.
- * @param {string} type An ONC network type
+ * Creates a callback function that shows the "add network" dialog for a VPN
+ * provider. If |opt_extensionID| is omitted, the dialog for the built-in
+ * OpenVPN/L2TP provider is shown. Otherwise, |opt_extensionID| identifies the
+ * third-party provider for which the dialog should be shown.
+ * @param {string=} opt_extensionID Extension ID identifying the third-party
+ * VPN provider for which the dialog should be shown.
* @return {function()} The created callback.
* @private
*/
- function createAddConnectionCallback_(type) {
+ function createVPNConnectionCallback_(opt_extensionID) {
return function() {
- if (type == 'WiFi')
- sendChromeMetricsAction('Options_NetworkJoinOtherWifi');
- else if (type == 'VPN')
- sendChromeMetricsAction('Options_NetworkJoinOtherVPN');
- chrome.send('addConnection', [type]);
+ sendChromeMetricsAction(opt_extensionID ?
+ 'Options_NetworkAddVPNThirdParty' :
+ 'Options_NetworkAddVPNBuiltIn');
+ chrome.send('addVPNConnection',
+ opt_extensionID ? [opt_extensionID] : undefined);
};
}
/**
+ * Generates an "add network" entry for each VPN provider currently enabled in
+ * the primary user's profile.
+ * @return {!Array<{label: string, command: function(), data: !Object}>} The
+ * list of entries.
+ * @private
+ */
+ function createAddVPNConnectionEntries_() {
+ var entries = [];
+ var providers = options.VPNProviders.getProviders();
+ for (var i = 0; i < providers.length; ++i) {
+ entries.push({
+ label: loadTimeData.getStringF('addConnectionVPNTemplate',
+ providers[i].name),
+ command: createVPNConnectionCallback_(
+ providers[i].extensionID || undefined),
+ data: {}
+ });
+ }
+ return entries;
+ }
+
+ /**
* Whether the Network list is disabled. Only used for display purpose.
*/
cr.defineProperty(NetworkList, 'disabled', cr.PropertyKind.BOOL_ATTR);
diff --git a/chromium/chrome/browser/resources/options/chromeos/onc_data.js b/chromium/chrome/browser/resources/options/chromeos/onc_data.js
index d6dfcf647fb..8114dbd2a33 100644
--- a/chromium/chrome/browser/resources/options/chromeos/onc_data.js
+++ b/chromium/chrome/browser/resources/options/chromeos/onc_data.js
@@ -21,6 +21,8 @@ cr.define('cr.onc', function() {
}
OncData.prototype = {
+ /** @return {string} The GUID of the network. */
+ guid: function() { return this.data_['GUID']; },
/**
* Returns either a managed property dictionary or an unmanaged value.
@@ -47,9 +49,9 @@ cr.define('cr.onc', function() {
* Sets the value of a property. Currently only supports unmanaged
* properties.
* @param {string} key The property key.
- * @param {Object} value The property value to set.
+ * @param {?} value The property value to set.
*/
- setManagedProperty: function(key, value) {
+ setProperty: function(key, value) {
var data = this.data_;
while (true) {
var index = key.indexOf('.');
@@ -177,6 +179,13 @@ cr.define('cr.onc', function() {
return property[effective];
}
return undefined;
+ },
+
+ /**
+ * Returns the complete ONC dictionary.
+ */
+ getData: function() {
+ return this.data_;
}
};
diff --git a/chromium/chrome/browser/resources/options/chromeos/preferred_networks.js b/chromium/chrome/browser/resources/options/chromeos/preferred_networks.js
index 8dd24ecf06c..4f5a152b03a 100644
--- a/chromium/chrome/browser/resources/options/chromeos/preferred_networks.js
+++ b/chromium/chrome/browser/resources/options/chromeos/preferred_networks.js
@@ -5,7 +5,7 @@
cr.exportPath('options');
/**
- * @typedef {{Name: string, Type: string, servicePath: string}}
+ * @typedef {{GUID: string, Name: string, Source: string, Type: string}}
*/
options.PreferredNetwork;
@@ -83,8 +83,10 @@ cr.define('options', function() {
DeletableItem.prototype.decorate.call(this);
var label = this.ownerDocument.createElement('div');
label.textContent = this.data.Name;
- if (this.data.policyManaged)
+ if (this.data.Source == 'DevicePolicy' ||
+ this.data.Source == 'UserPolicy') {
this.deletable = false;
+ }
this.contentElement.appendChild(label);
}
};
@@ -125,11 +127,8 @@ cr.define('options', function() {
/** @override */
deleteItemAtIndex: function(index) {
var item = this.dataModel.item(index);
- if (item) {
- // TODO(stevenjb): Add removeNetwork to chrome.networkingPrivate and
- // use that here.
- chrome.send('removeNetwork', [item.servicePath]);
- }
+ if (item)
+ chrome.networkingPrivate.forgetNetwork(item.GUID);
this.dataModel.splice(index, 1);
// Invalidate the list since it has a stale cache after a splice
// involving a deletion.
diff --git a/chromium/chrome/browser/resources/options/chromeos/vpn_providers.js b/chromium/chrome/browser/resources/options/chromeos/vpn_providers.js
new file mode 100644
index 00000000000..06da41b5339
--- /dev/null
+++ b/chromium/chrome/browser/resources/options/chromeos/vpn_providers.js
@@ -0,0 +1,123 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview A singleton that keeps track of the VPN providers enabled in
+ * the primary user's profile.
+ */
+
+cr.define('options', function() {
+ /**
+ * @constructor
+ */
+ function VPNProviders() {
+ }
+
+ cr.addSingletonGetter(VPNProviders);
+
+ VPNProviders.prototype = {
+ /**
+ * The VPN providers enabled in the primary user's profile. Each provider
+ * has a name. Third-party VPN providers additionally have an extension ID.
+ * @type {!Array<{name: string, extensionID: ?string}>}
+ * @private
+ */
+ providers_: [],
+
+ /**
+ * Observers who will be called when the list of VPN providers changes.
+ * @type {!Array<!function()>}
+ */
+ observers_: [],
+
+ /**
+ * The VPN providers enabled in the primary user's profile.
+ * @type {!Array<{name: string, extensionID: ?string}>}
+ */
+ get providers() {
+ return this.providers_;
+ },
+ set providers(providers) {
+ this.providers_ = providers;
+ for (var i = 0; i < this.observers_.length; ++i)
+ this.observers_[i]();
+ },
+
+ /**
+ * Adds an observer to be called when the list of VPN providers changes.
+ * @param {!function()} observer The observer to add.
+ * @private
+ */
+ addObserver_: function(observer) {
+ this.observers_.push(observer);
+ },
+
+ /**
+ * Formats a network name for display purposes. If the network belongs to
+ * a third-party VPN provider, the provider name is added to the network
+ * name.
+ * @param {cr.onc.OncData} onc ONC data describing this network.
+ * @return {string} The resulting display name.
+ * @private
+ */
+ formatNetworkName_: function(onc) {
+ var networkName = onc.getTranslatedValue('Name');
+ if (onc.getActiveValue('VPN.Type') != 'ThirdPartyVPN')
+ return networkName;
+ var extensionID = onc.getActiveValue('VPN.ThirdPartyVPN.ExtensionID');
+ for (var i = 0; i < this.providers_.length; ++i) {
+ if (extensionID == this.providers_[i].extensionID) {
+ return loadTimeData.getStringF('vpnNameTemplate',
+ this.providers_[i].name,
+ networkName);
+ }
+ }
+ return networkName;
+ },
+ };
+
+ /**
+ * Adds an observer to be called when the list of VPN providers changes. Note
+ * that an observer may in turn call setProviders() but should be careful not
+ * to get stuck in an infinite loop as every change to the list of VPN
+ * providers will cause the observers to be called again.
+ * @param {!function()} observer The observer to add.
+ */
+ VPNProviders.addObserver = function(observer) {
+ VPNProviders.getInstance().addObserver_(observer);
+ };
+
+ /**
+ * Returns the list of VPN providers enabled in the primary user's profile.
+ * @return {!Array<{name: string, extensionID: ?string}>} The list of VPN
+ * providers enabled in the primary user's profile.
+ */
+ VPNProviders.getProviders = function() {
+ return VPNProviders.getInstance().providers;
+ };
+
+ /**
+ * Replaces the list of VPN providers enabled in the primary user's profile.
+ * @param {!Array<{name: string, extensionID: ?string}>} providers The list
+ * of VPN providers enabled in the primary user's profile.
+ */
+ VPNProviders.setProviders = function(providers) {
+ VPNProviders.getInstance().providers = providers;
+ };
+
+ /**
+ * Formats a network name for display purposes. If the network belongs to a
+ * third-party VPN provider, the provider name is added to the network name.
+ * @param {cr.onc.OncData} onc ONC data describing this network.
+ * @return {string} The resulting display name.
+ */
+ VPNProviders.formatNetworkName = function(onc) {
+ return VPNProviders.getInstance().formatNetworkName_(onc);
+ };
+
+ // Export
+ return {
+ VPNProviders: VPNProviders
+ };
+});