blob: 1a1ae37c7c8129b66a14d44e12886afb5ef867d7 [file] [log] [blame]
// 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 Polymer element for displaying a summary of network states
* by type: Ethernet, WiFi, Cellular, WiMAX, and VPN.
*/
/** @typedef {chrome.networkingPrivate.DeviceStateProperties} */
var DeviceStateProperties;
/**
* @typedef {{
* Ethernet: (DeviceStateProperties|undefined),
* WiFi: (DeviceStateProperties|undefined),
* Cellular: (DeviceStateProperties|undefined),
* WiMAX: (DeviceStateProperties|undefined),
* VPN: (DeviceStateProperties|undefined)
* }}
*/
var DeviceStateObject;
/**
* @typedef {{
* Ethernet: (Array<CrOnc.NetworkStateProperties>|undefined),
* WiFi: (Array<CrOnc.NetworkStateProperties>|undefined),
* Cellular: (Array<CrOnc.NetworkStateProperties>|undefined),
* WiMAX: (Array<CrOnc.NetworkStateProperties>|undefined),
* VPN: (Array<CrOnc.NetworkStateProperties>|undefined)
* }}
*/
var NetworkStateListObject;
Polymer({
is: 'network-summary',
properties: {
/**
* Highest priority connected network or null.
* @type {?CrOnc.NetworkStateProperties}
*/
defaultNetwork: {
type: Object,
value: null,
notify: true,
},
/**
* Interface for networkingPrivate calls, passed from internet_page.
* @type {NetworkingPrivate}
*/
networkingPrivate: Object,
/**
* The device state for each network device type.
* @private {DeviceStateObject}
*/
deviceStates_: {
type: Object,
value: function() {
return {};
},
},
/**
* Array of active network states, one per device type.
* @private {!Array<!CrOnc.NetworkStateProperties>}
*/
activeNetworkStates_: {
type: Array,
value: function() {
return [];
},
},
/**
* List of network state data for each network type.
* @private {NetworkStateListObject}
*/
networkStateLists_: {
type: Object,
value: function() {
return {};
},
},
},
/**
* Listener function for chrome.networkingPrivate.onNetworkListChanged event.
* @type {function(!Array<string>)}
* @private
*/
networkListChangedListener_: function() {},
/**
* Listener function for chrome.networkingPrivate.onDeviceStateListChanged
* event.
* @type {function(!Array<string>)}
* @private
*/
deviceStateListChangedListener_: function() {},
/**
* Listener function for chrome.networkingPrivate.onNetworksChanged event.
* @type {function(!Array<string>)}
* @private
*/
networksChangedListener_: function() {},
/**
* Set of GUIDs identifying active networks, one for each type.
* @type {?Set<string>}
* @private
*/
activeNetworkIds_: null,
/** @override */
attached: function() {
this.getNetworkLists_();
this.networkListChangedListener_ =
this.onNetworkListChangedEvent_.bind(this);
this.networkingPrivate.onNetworkListChanged.addListener(
this.networkListChangedListener_);
this.deviceStateListChangedListener_ =
this.onDeviceStateListChangedEvent_.bind(this);
this.networkingPrivate.onDeviceStateListChanged.addListener(
this.deviceStateListChangedListener_);
this.networksChangedListener_ = this.onNetworksChangedEvent_.bind(this);
this.networkingPrivate.onNetworksChanged.addListener(
this.networksChangedListener_);
},
/** @override */
detached: function() {
this.networkingPrivate.onNetworkListChanged.removeListener(
this.networkListChangedListener_);
this.networkingPrivate.onDeviceStateListChanged.removeListener(
this.deviceStateListChangedListener_);
this.networkingPrivate.onNetworksChanged.removeListener(
this.networksChangedListener_);
},
/**
* Event triggered when the network-summary-item is expanded.
* @param {!{detail: {expanded: boolean, type: string}}} event
* @private
*/
onExpanded_: function(event) {
if (!event.detail.expanded)
return;
// Get the latest network states.
this.getNetworkStates_();
if (event.detail.type == CrOnc.Type.WI_FI)
this.networkingPrivate.requestNetworkScan();
},
/**
* Event triggered when a network-summary-item is selected.
* @param {!{detail: !CrOnc.NetworkStateProperties}} event
* @private
*/
onSelected_: function(event) {
var state = event.detail;
if (this.canConnect_(state)) {
this.connectToNetwork_(state);
return;
}
this.fire('show-detail', state);
},
/**
* Event triggered when the enabled state of a network-summary-item is
* toggled.
* @param {!{detail: {enabled: boolean,
* type: chrome.networkingPrivate.NetworkType}}} event
* @private
*/
onDeviceEnabledToggled_: function(event) {
if (event.detail.enabled)
this.networkingPrivate.enableNetworkType(event.detail.type);
else
this.networkingPrivate.disableNetworkType(event.detail.type);
},
/**
* networkingPrivate.onNetworkListChanged event callback.
* @private
*/
onNetworkListChangedEvent_: function() {
this.getNetworkLists_();
},
/**
* networkingPrivate.onDeviceStateListChanged event callback.
* @private
*/
onDeviceStateListChangedEvent_: function() {
this.getNetworkLists_();
},
/**
* networkingPrivate.onNetworksChanged event callback.
* @param {!Array<string>} networkIds The list of changed network GUIDs.
* @private
*/
onNetworksChangedEvent_: function(networkIds) {
if (!this.activeNetworkIds_)
return; // Initial list of networks not received yet.
networkIds.forEach(function(id) {
if (this.activeNetworkIds_.has(id)) {
this.networkingPrivate.getState(
id, this.getActiveStateCallback_.bind(this, id));
}
}, this);
},
/**
* Determines whether or not a network state can be connected to.
* @param {!CrOnc.NetworkStateProperties} state The network state.
* @private
*/
canConnect_: function(state) {
if (state.Type == CrOnc.Type.ETHERNET ||
state.Type == CrOnc.Type.VPN && !this.defaultNetwork) {
return false;
}
return state.ConnectionState == CrOnc.ConnectionState.NOT_CONNECTED;
},
/**
* networkingPrivate.getState event callback for an active state.
* @param {string} id The id of the requested state.
* @param {!chrome.networkingPrivate.NetworkStateProperties} state
* @private
*/
getActiveStateCallback_: function(id, state) {
if (chrome.runtime.lastError) {
var message = chrome.runtime.lastError.message;
if (message != 'Error.NetworkUnavailable') {
console.error(
'Unexpected networkingPrivate.getState error: ' + message +
' For: ' + id);
}
return;
}
// Async call, ensure id still exists.
if (!this.activeNetworkIds_.has(id))
return;
if (!state) {
this.activeNetworkIds_.delete(id);
return;
}
// Find the active state for the type and update it.
for (let i = 0; i < this.activeNetworkStates_.length; ++i) {
if (this.activeNetworkStates_[i].type == state.type) {
this.activeNetworkStates_[i] = state;
return;
}
}
// Not found
console.error('Active state not found: ' + state.Name);
},
/**
* Handles UI requests to connect to a network.
* TODO(stevenjb): Handle Cellular activation, etc.
* @param {!CrOnc.NetworkStateProperties} state The network state.
* @private
*/
connectToNetwork_: function(state) {
this.networkingPrivate.startConnect(state.GUID, function() {
if (chrome.runtime.lastError) {
var message = chrome.runtime.lastError.message;
if (message != 'connecting') {
console.error(
'Unexpected networkingPrivate.startConnect error: ' + message +
'For: ' + state.GUID);
}
}
});
},
/**
* Requests the list of device states and network states from Chrome.
* Updates deviceStates, activeNetworkStates, and networkStateLists once the
* results are returned from Chrome.
* @private
*/
getNetworkLists_: function() {
// First get the device states.
this.networkingPrivate.getDeviceStates(function(deviceStates) {
// Second get the network states.
this.getNetworkStates_(deviceStates);
}.bind(this));
},
/**
* Requests the list of network states from Chrome. Updates
* activeNetworkStates and networkStateLists once the results are returned
* from Chrome.
* @param {!Array<!DeviceStateProperties>=} opt_deviceStates
* Optional list of state properties for all available devices.
* @private
*/
getNetworkStates_: function(opt_deviceStates) {
var filter = {
networkType: chrome.networkingPrivate.NetworkType.ALL,
visible: true,
configured: false
};
this.networkingPrivate.getNetworks(filter, function(networkStates) {
this.updateNetworkStates_(networkStates, opt_deviceStates);
}.bind(this));
},
/**
* Called after network states are received from getNetworks.
* @param {!Array<!CrOnc.NetworkStateProperties>} networkStates The state
* properties for all visible networks.
* @param {!Array<!DeviceStateProperties>=} opt_deviceStates
* Optional list of state properties for all available devices. If not
* defined the existing list of device states will be used.
* @private
*/
updateNetworkStates_: function(networkStates, opt_deviceStates) {
var newDeviceStates;
if (opt_deviceStates) {
newDeviceStates = /** @type {!DeviceStateObject} */ ({});
for (let state of opt_deviceStates)
newDeviceStates[state.Type] = state;
} else {
newDeviceStates = this.deviceStates_;
}
// Clear any current networks.
var activeNetworkStatesByType =
/** @type {!Map<string, !CrOnc.NetworkStateProperties>} */ (new Map);
// Complete list of states by type.
/** @type {!NetworkStateListObject} */ var newNetworkStateLists = {
Ethernet: [],
WiFi: [],
Cellular: [],
WiMAX: [],
VPN: [],
};
var firstConnectedNetwork = null;
networkStates.forEach(function(state) {
let type = state.Type;
if (!activeNetworkStatesByType.has(type)) {
activeNetworkStatesByType.set(type, state);
if (!firstConnectedNetwork && state.Type != CrOnc.Type.VPN &&
state.ConnectionState == CrOnc.ConnectionState.CONNECTED) {
firstConnectedNetwork = state;
}
}
newNetworkStateLists[type].push(state);
}, this);
this.defaultNetwork = firstConnectedNetwork;
// Create a VPN entry in deviceStates if there are any VPN networks.
if (newNetworkStateLists.VPN && newNetworkStateLists.VPN.length > 0) {
newDeviceStates.VPN = /** @type {DeviceStateProperties} */ ({
Type: CrOnc.Type.VPN,
State: chrome.networkingPrivate.DeviceStateType.ENABLED
});
}
// Push the active networks onto newActiveNetworkStates in order based on
// device priority, creating an empty state for devices with no networks.
let newActiveNetworkStates = [];
this.activeNetworkIds_ = new Set;
let orderedDeviceTypes = [
CrOnc.Type.ETHERNET, CrOnc.Type.WI_FI, CrOnc.Type.CELLULAR,
CrOnc.Type.WI_MAX, CrOnc.Type.VPN
];
for (let type of orderedDeviceTypes) {
let device = newDeviceStates[type];
if (!device)
continue;
let state = activeNetworkStatesByType.get(type) || {GUID: '', Type: type};
newActiveNetworkStates.push(state);
this.activeNetworkIds_.add(state.GUID);
}
this.deviceStates_ = newDeviceStates;
this.networkStateLists_ = newNetworkStateLists;
// Set activeNetworkStates last to rebuild the dom-repeat.
this.activeNetworkStates_ = newActiveNetworkStates;
},
});