Commit 6014e9a1 authored by stevenjb's avatar stevenjb Committed by Commit bot

Support badges and connecting animation in cr-network-icon element

This is a follow-up to https://codereview.chromium.org/874283006
which introduces the cr-network-icon Polymer element for
displaying an icon representing network state in web UI.

It also includes minor changes to the fake shill implementation to facilitate manual testing.

BUG=455499

Review URL: https://codereview.chromium.org/954293003

Cr-Commit-Position: refs/heads/master@{#318824}
parent 6ad356d3
......@@ -50,6 +50,11 @@ paper-button[raised].colored {
font-weight: bold;
}
.state-table-icon-cell {
display: flex;
justify-content: center;
}
.state-table-expand-button-cell {
text-align: center;
}
......
......@@ -261,6 +261,7 @@ const char kPowerStub[] = "power-stub";
// Overrides network stub behavior. By default, ethernet, wifi and vpn are
// enabled, and transitions occur instantaneously. Multiple options can be
// comma separated (no spaces). Note: all options are in the format 'foo=x'.
// Values are case sensitive and based on Shill names in service_constants.h.
// See FakeShillManagerClient::SetInitialNetworkState for implementation.
// Examples:
// 'clear=1' - Clears all default configurations
......@@ -270,6 +271,7 @@ const char kPowerStub[] = "power-stub";
// 'wifi=none' - Wifi is unavailable
// 'wifi=portal' - Wifi connection will be in Portal state
// 'cellular=1' - Cellular is initially connected
// 'cellular=LTE' - Cellular is initially connected, technology is LTE
// 'interactive=3' - Interactive mode, connect/scan/etc requests take 3 secs
const char kShillStub[] = "shill-stub";
......
......@@ -105,6 +105,19 @@ void UpdatePortaledWifiState(const std::string& service_path) {
base::StringValue(shill::kStatePortal));
}
bool IsCellularTechnology(const std::string& type) {
return (type == shill::kNetworkTechnology1Xrtt ||
type == shill::kNetworkTechnologyEvdo ||
type == shill::kNetworkTechnologyGsm ||
type == shill::kNetworkTechnologyGprs ||
type == shill::kNetworkTechnologyEdge ||
type == shill::kNetworkTechnologyUmts ||
type == shill::kNetworkTechnologyHspa ||
type == shill::kNetworkTechnologyHspaPlus ||
type == shill::kNetworkTechnologyLte ||
type == shill::kNetworkTechnologyLteAdvanced);
}
const char* kTechnologyUnavailable = "unavailable";
const char* kNetworkActivated = "activated";
const char* kNetworkDisabled = "disabled";
......@@ -118,6 +131,7 @@ const char FakeShillManagerClient::kFakeEthernetNetworkGuid[] = "eth1_guid";
FakeShillManagerClient::FakeShillManagerClient()
: interactive_delay_(0),
cellular_technology_(shill::kNetworkTechnologyGsm),
weak_ptr_factory_(this) {
ParseCommandLineSwitch();
}
......@@ -776,7 +790,7 @@ void FakeShillManagerClient::SetupDefaultEnvironment() {
shill::kTypeCellular,
state,
add_to_visible);
base::StringValue technology_value(shill::kNetworkTechnologyGsm);
base::StringValue technology_value(cellular_technology_);
devices->SetDeviceProperty("/device/cellular1",
shill::kTechnologyFamilyProperty,
technology_value);
......@@ -1066,7 +1080,6 @@ bool FakeShillManagerClient::ParseOption(const std::string& arg0,
bool FakeShillManagerClient::SetInitialNetworkState(std::string type_arg,
std::string state_arg) {
std::string state;
state_arg = base::StringToLowerASCII(state_arg);
if (state_arg.empty() || state_arg == "1" || state_arg == "on" ||
state_arg == "enabled" || state_arg == "connected" ||
state_arg == "online") {
......@@ -1088,12 +1101,20 @@ bool FakeShillManagerClient::SetInitialNetworkState(std::string type_arg,
} else if (state_arg == "active" || state_arg == "activated") {
// Technology is enabled, a service is connected and Activated.
state = kNetworkActivated;
} else if (type_arg == shill::kTypeCellular &&
IsCellularTechnology(state_arg)) {
state = shill::kStateOnline;
cellular_technology_ = state_arg;
} else if (type_arg == shill::kTypeCellular && state_arg == "LTEAdvanced") {
// Special case, Shill name contains a ' '.
state = shill::kStateOnline;
cellular_technology_ = shill::kNetworkTechnologyLteAdvanced;
} else {
LOG(ERROR) << "Unrecognized initial state: " << state_arg;
LOG(ERROR) << "Unrecognized initial state: " << type_arg << "="
<< state_arg;
return false;
}
type_arg = base::StringToLowerASCII(type_arg);
// Special cases
if (type_arg == "wireless") {
shill_initial_state_map_[shill::kTypeWifi] = state;
......
......@@ -142,6 +142,9 @@ class CHROMEOS_EXPORT FakeShillManagerClient
// Initial state for fake services.
std::map<std::string, std::string> shill_initial_state_map_;
// Technology type for fake cellular service.
std::string cellular_technology_;
// Roaming state for fake cellular service.
std::string roaming_state_;
......
......@@ -4,8 +4,10 @@
:host {
display: inline-block;
height: 50px;
overflow: hidden;
position: relative;
width: 50px;
}
#icon {
......@@ -38,10 +40,39 @@
top: -400%;
}
/* Connecting animation */
#icon.connecting {
-webkit-animation: levels 1s infinite;
-webkit-animation-timing-function: steps(4, start);
}
@-webkit-keyframes levels {
from {
top: 0%;
}
to {
top: -400%;
}
}
/* Badges. */
/* Note: These use left/right because we do not reverse the badges for RTL. */
/* Upper-left corner */
#technology {
height: 40%;
left: 0px;
position: absolute;
top: 0px;
}
/* Lower-right corner */
#roaming,
#secure {
height: 40%;
margin-left: 60%;
margin-top: 60%;
left: 60%;
position: absolute;
top: 60%;
width: 40%;
}
......@@ -3,9 +3,15 @@
<polymer-element name="cr-network-icon">
<template>
<link rel="stylesheet" href="cr_network_icon.css">
<img id="icon">
<img id="icon" src="{{iconType | toImageSrc}}">
<img id="technology" src="{{technology | toBadgeImageSrc}}"
hidden?="{{!technology}}">
<img id="roaming"
src="chrome://resources/cr_elements/cr_network_icon/badge_roaming.png"
hidden?="{{!roaming}}">
<img id="secure"
src="chrome://resources/cr_elements/cr_network_icon/secure.png">
src="chrome://resources/cr_elements/cr_network_icon/badge_secure.png"
hidden?="{{!secure}}">
</template>
<script src="cr_network_icon.js"></script>
</polymer-element>
......@@ -10,10 +10,8 @@
(function() {
/**
* @typedef {{
* showBadges: boolean,
* showDisconnected: boolean,
* iconType: string,
* connected: boolean,
* secure: boolean,
* strength: number
* }}
*/
......@@ -51,6 +49,30 @@ function getIconTypeFromNetworkType(networkType) {
* @element cr-network-icon
*/
Polymer('cr-network-icon', {
/**
* The icon type to use for the base image of the icon.
* @type string
*/
iconType: 'ethernet',
/**
* Set to true to show a badge for roaming networks.
* @type boolean
*/
roaming: false,
/**
* Set to true to show a badge for secure networks.
* @type boolean
*/
secure: false,
/**
* Set to the name of a technology to show show a badge.
* @type string
*/
technology: '',
publish: {
/**
* If set, the ONC data properties will be used to display the icon.
......@@ -85,9 +107,7 @@ Polymer('cr-network-icon', {
/** @override */
attached: function() {
var params = /** @type {IconParams} */ {
connected: false,
iconType: 'ethernet',
secure: false,
showBadges: false,
showDisconnected: true,
strength: 0,
};
......@@ -99,12 +119,9 @@ Polymer('cr-network-icon', {
* network state.
*/
networkStateChanged: function() {
var iconType = getIconTypeFromNetworkType(this.networkState.data.Type);
this.iconType = getIconTypeFromNetworkType(this.networkState.data.Type);
var params = /** @type {IconParams} */ {
connected: this.networkState.data.ConnectionState == 'Connected',
iconType: iconType,
secure: iconType == 'wifi' &&
this.networkState.getWiFiSecurity() != 'None',
showBadges: true,
showDisconnected: !this.isListItem,
strength: this.networkState.getStrength(),
};
......@@ -116,16 +133,33 @@ Polymer('cr-network-icon', {
* of network, showing a disconnected icon where appropriate and no badges.
*/
networkTypeChanged: function() {
this.iconType = getIconTypeFromNetworkType(this.networkType);
var params = /** @type {IconParams} */ {
connected: false,
iconType: getIconTypeFromNetworkType(this.networkType),
secure: false,
showBadges: false,
showDisconnected: true,
strength: 0,
};
this.setIcon_(params);
},
/**
* Returns the url for an image based on identifier |id|.
* @param {string} src The identifier describing the image.
* @return {string} The url to use for the image 'src' property.
*/
toImageSrc: function(id) {
return id ? RESOURCE_IMAGE_BASE + id + RESOURCE_IMAGE_EXT : '';
},
/**
* Returns the url for a badge image based on identifier |id|.
* @param {string} id The identifier describing the badge.
* @return {string} The url to use for the badge image 'src' property.
*/
toBadgeImageSrc: function(id) {
return id ? this.toImageSrc('badge_' + id) : '';
},
/**
* Sets the icon and badge based on the current state and |strength|.
* @param {!IconParams} params The set of params describing the icon.
......@@ -133,26 +167,102 @@ Polymer('cr-network-icon', {
*/
setIcon_: function(params) {
var icon = this.$.icon;
if (params.iconType)
icon.src = RESOURCE_IMAGE_BASE + params.iconType + RESOURCE_IMAGE_EXT;
var multiLevel, strength;
if (params.iconType == 'wifi' || params.iconType == 'mobile') {
multiLevel = true;
strength = (params.showDisconnected && !params.connected) ?
-1 : params.strength;
var multiLevel = (this.iconType == 'wifi' || this.iconType == 'mobile');
if (this.networkState && multiLevel) {
this.setMultiLevelIcon_(params);
} else {
multiLevel = false;
strength = -1;
icon.className = multiLevel ? 'multi-level level0' : '';
}
this.setIconBadges_(params);
},
/**
* Toggles icon classes based on strength and connecting properties.
* |this.networkState| is expected to be specified.
* @param {!IconParams} params The set of params describing the icon.
* @private
*/
setMultiLevelIcon_: function(params) {
// Set the strength or connecting properties.
var networkState = this.networkState;
var connecting = false;
var strength = -1;
if (networkState.connecting()) {
strength = 0;
connecting = true;
} else if (networkState.connected() || !params.showDisconnected) {
strength = params.strength || 0;
}
icon.classList.toggle('multi-level', multiLevel);
var icon = this.$.icon;
icon.classList.toggle('multi-level', true);
icon.classList.toggle('connecting', connecting);
icon.classList.toggle('level0', strength < 0);
icon.classList.toggle('level1', strength >= 0 && strength <= 25);
icon.classList.toggle('level2', strength > 25 && strength <= 50);
icon.classList.toggle('level3', strength > 50 && strength <= 75);
icon.classList.toggle('level4', strength > 75);
},
/**
* Sets the icon badge visibility properties: roaming, secure, technology.
* @param {!IconParams} params The set of params describing the icon.
* @private
*/
setIconBadges_: function(params) {
var networkState = this.networkState;
this.$.secure.hidden = !params.secure;
var type =
(params.showBadges && networkState) ? networkState.data.Type : '';
if (type == CrOnc.Type.WIFI) {
this.roaming = false;
this.secure = networkState.getWiFiSecurity() != 'None';
this.technology = '';
} else if (type == CrOnc.Type.WIMAX) {
this.roaming = false;
this.secure = false;
this.technology = '4g';
} else if (type == CrOnc.Type.CELLULAR) {
this.roaming =
networkState.getCellularRoamingState() == CrOnc.RoamingState.ROAMING;
this.secure = false;
var oncTechnology = networkState.getCellularTechnology();
switch (oncTechnology) {
case CrOnc.NetworkTechnology.EDGE:
this.technology = 'edge';
break;
case CrOnc.NetworkTechnology.EVDO:
this.technology = 'evdo';
break;
case CrOnc.NetworkTechnology.GPRS:
case CrOnc.NetworkTechnology.GSM:
this.technology = 'gsm';
break;
case CrOnc.NetworkTechnology.HSPA:
this.technology = 'hspa';
break;
case CrOnc.NetworkTechnology.HSPA_PLUS:
this.technology = 'hspa_plus';
break;
case CrOnc.NetworkTechnology.LTE:
this.technology = 'lte';
break;
case CrOnc.NetworkTechnology.LTE_ADVANCED:
this.technology = 'lte_advanced';
break;
case CrOnc.NetworkTechnology.UMTS:
this.technology = '3g';
break;
}
} else {
this.roaming = false;
this.secure = false;
this.technology = '';
}
},
});
})();
......@@ -22,13 +22,22 @@ Polymer('cr-onc-data', {
data: null,
},
/** @override */
created: function() {
this.data = /** @type {CrOnc.NetworkConfigType} */({});
},
/**
* @return {number} The signal strength of the network.
*/
/** @return {boolean} True if the network is connected. */
connected: function() {
return this.data.ConnectionState == CrOnc.ConnectionState.CONNECTED;
},
/** @return {boolean} True if the network is connecting. */
connecting: function() {
return this.data.ConnectionState == CrOnc.ConnectionState.CONNECTING;
},
/** @return {number} The signal strength of the network. */
getStrength: function() {
var type = this.data.Type;
var strength = 0;
......@@ -41,12 +50,21 @@ Polymer('cr-onc-data', {
return strength;
},
/**
* Returns the WiFi security type. Undefined or empty defaults to 'None'.
* @return {string} The WiFi security type.
*/
/** @return {CrOnc.Security} The ONC security type. */
getWiFiSecurity: function() {
return (this.data.WiFi && this.data.WiFi.Security) ?
this.data.WiFi.Security : 'None';
this.data.WiFi.Security : CrOnc.Security.NONE;
},
/** @return {CrOnc.RoamingState} The ONC roaming state. */
getCellularRoamingState: function() {
return (this.data.Cellular && this.data.Cellular.RoamingState) ?
this.data.Cellular.RoamingState : CrOnc.RoamingState.UNKNOWN;
},
/** @return {CrOnc.NetworkTechnology} The ONC network technology. */
getCellularTechnology: function() {
return (this.data.Cellular && this.data.Cellular.NetworkTechnology) ?
this.data.Cellular.NetworkTechnology : CrOnc.NetworkTechnology.UNKNOWN;
}
});
......@@ -12,16 +12,67 @@
var CrOnc = {};
/** @enum {string} */
CrOnc.Type = {
CELLULAR: 'Cellular',
ETHERNET: 'Ethernet',
VPN: 'VPN',
WIFI: 'WiFi',
WIMAX: 'WiMAX',
};
/** @enum {string} */
CrOnc.ConnectionState = {
CONNECTED: 'Connected',
CONNECTING: 'Connecting',
NOT_CONNECTED: 'NotConnected',
};
/** @enum {string} */
CrOnc.NetworkTechnology = {
EDGE: 'EDGE',
EVDO: 'EVDO',
GPRS: 'GPRS',
GSM: 'GSM',
HSPA: 'HSPA',
HSPA_PLUS: 'HSPA+',
LTE: 'LTE',
LTE_ADVANCED: 'LTE Advanced',
UMTS: 'UMTS',
UNKNOWN: 'Unknown',
};
/** @enum {string} */
CrOnc.RoamingState = {
HOME: 'Home',
REQUIRED: 'Required',
ROAMING: 'Roaming',
UNKNOWN: 'Unknown',
};
/** @enum {string} */
CrOnc.Security = {
NONE: 'None',
WEP_8021X: 'WEP-8021X',
WEP_PSK: 'WEP-PSK',
WPA_EAP: 'WPA-EAP',
WPA_PSK: 'WPA-PSK',
};
/** @typedef {string|!Object} */
CrOnc.ManagedStringType;
/**
* @typedef {{NetworkTechnology: string, Strength: number}}
* @typedef {{
* NetworkTechnology: CrOnc.NetworkTechnology,
* RoamingState: CrOnc.RoamingState,
* Strength: number
* }}
*/
CrOnc.CellularType;
/**
* @typedef {{Security: string, Strength: number}}
* @typedef {{Security: CrOnc.Security, Strength: number}}
*/
CrOnc.WiFiType;
......@@ -30,22 +81,13 @@ CrOnc.WiFiType;
*/
CrOnc.WiMAXType;
/** @enum {string} */
CrOnc.Type = {
CELLULAR: "Cellular",
ETHERNET: "Ethernet",
VPN: "VPN",
WIFI: "WiFi",
WIMAX: "WiMAX",
};
/**
* @typedef {{
* Cellular: CrOnc.CellularType,
* ConnectionState: string,
* ConnectionState: CrOnc.ConnectionState,
* GUID: string,
* Name: CrOnc.ManagedStringType,
* Type: string,
* Type: CrOnc.Type,
* WiFi: CrOnc.WiFiType,
* WiMAX: CrOnc.WiMAXType
* }}
......
<?xml version="1.0" encoding="utf-8"?>
<grit-part>
<include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_3G"
file="cr_elements/cr_network_icon/badge_3g.png"
type="BINDATA" />
<include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_4G"
file="cr_elements/cr_network_icon/badge_4g.png"
type="BINDATA" />
<include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_EDGE"
file="cr_elements/cr_network_icon/badge_edge.png"
type="BINDATA" />
<include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_EVDO"
file="cr_elements/cr_network_icon/badge_evdo.png"
type="BINDATA" />
<include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_GPRS"
file="cr_elements/cr_network_icon/badge_gsm.png"
type="BINDATA" />
<include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_HSPA"
file="cr_elements/cr_network_icon/badge_hspa.png"
type="BINDATA" />
<include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_HSPA_PLUS"
file="cr_elements/cr_network_icon/badge_hspa_plus.png"
type="BINDATA" />
<include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_LTE"
file="cr_elements/cr_network_icon/badge_lte.png"
type="BINDATA" />
<include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_LTE_ADVANCED"
file="cr_elements/cr_network_icon/badge_lte_advanced.png"
type="BINDATA" />
<include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_ROAMING"
file="cr_elements/cr_network_icon/badge_roaming.png"
type="BINDATA" />
<include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_SECURE"
file="cr_elements/cr_network_icon/badge_secure.png"
type="BINDATA" />
<include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_ETHERNET"
file="cr_elements/cr_network_icon/ethernet.png"
type="BINDATA" />
<include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_WIFI"
file="cr_elements/cr_network_icon/wifi.png"
type="BINDATA" />
<include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_MOBILE"
file="cr_elements/cr_network_icon/mobile.png"
type="BINDATA" />
<include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_VPN"
file="cr_elements/cr_network_icon/vpn.png"
type="BINDATA" />
<include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_SECURE"
file="cr_elements/cr_network_icon/secure.png"
<include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_WIFI"
file="cr_elements/cr_network_icon/wifi.png"
type="BINDATA" />
</grit-part>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment