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 { ...@@ -50,6 +50,11 @@ paper-button[raised].colored {
font-weight: bold; font-weight: bold;
} }
.state-table-icon-cell {
display: flex;
justify-content: center;
}
.state-table-expand-button-cell { .state-table-expand-button-cell {
text-align: center; text-align: center;
} }
......
...@@ -261,6 +261,7 @@ const char kPowerStub[] = "power-stub"; ...@@ -261,6 +261,7 @@ const char kPowerStub[] = "power-stub";
// Overrides network stub behavior. By default, ethernet, wifi and vpn are // Overrides network stub behavior. By default, ethernet, wifi and vpn are
// enabled, and transitions occur instantaneously. Multiple options can be // enabled, and transitions occur instantaneously. Multiple options can be
// comma separated (no spaces). Note: all options are in the format 'foo=x'. // 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. // See FakeShillManagerClient::SetInitialNetworkState for implementation.
// Examples: // Examples:
// 'clear=1' - Clears all default configurations // 'clear=1' - Clears all default configurations
...@@ -270,6 +271,7 @@ const char kPowerStub[] = "power-stub"; ...@@ -270,6 +271,7 @@ const char kPowerStub[] = "power-stub";
// 'wifi=none' - Wifi is unavailable // 'wifi=none' - Wifi is unavailable
// 'wifi=portal' - Wifi connection will be in Portal state // 'wifi=portal' - Wifi connection will be in Portal state
// 'cellular=1' - Cellular is initially connected // '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 // 'interactive=3' - Interactive mode, connect/scan/etc requests take 3 secs
const char kShillStub[] = "shill-stub"; const char kShillStub[] = "shill-stub";
......
...@@ -105,6 +105,19 @@ void UpdatePortaledWifiState(const std::string& service_path) { ...@@ -105,6 +105,19 @@ void UpdatePortaledWifiState(const std::string& service_path) {
base::StringValue(shill::kStatePortal)); 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* kTechnologyUnavailable = "unavailable";
const char* kNetworkActivated = "activated"; const char* kNetworkActivated = "activated";
const char* kNetworkDisabled = "disabled"; const char* kNetworkDisabled = "disabled";
...@@ -118,6 +131,7 @@ const char FakeShillManagerClient::kFakeEthernetNetworkGuid[] = "eth1_guid"; ...@@ -118,6 +131,7 @@ const char FakeShillManagerClient::kFakeEthernetNetworkGuid[] = "eth1_guid";
FakeShillManagerClient::FakeShillManagerClient() FakeShillManagerClient::FakeShillManagerClient()
: interactive_delay_(0), : interactive_delay_(0),
cellular_technology_(shill::kNetworkTechnologyGsm),
weak_ptr_factory_(this) { weak_ptr_factory_(this) {
ParseCommandLineSwitch(); ParseCommandLineSwitch();
} }
...@@ -776,7 +790,7 @@ void FakeShillManagerClient::SetupDefaultEnvironment() { ...@@ -776,7 +790,7 @@ void FakeShillManagerClient::SetupDefaultEnvironment() {
shill::kTypeCellular, shill::kTypeCellular,
state, state,
add_to_visible); add_to_visible);
base::StringValue technology_value(shill::kNetworkTechnologyGsm); base::StringValue technology_value(cellular_technology_);
devices->SetDeviceProperty("/device/cellular1", devices->SetDeviceProperty("/device/cellular1",
shill::kTechnologyFamilyProperty, shill::kTechnologyFamilyProperty,
technology_value); technology_value);
...@@ -1066,7 +1080,6 @@ bool FakeShillManagerClient::ParseOption(const std::string& arg0, ...@@ -1066,7 +1080,6 @@ bool FakeShillManagerClient::ParseOption(const std::string& arg0,
bool FakeShillManagerClient::SetInitialNetworkState(std::string type_arg, bool FakeShillManagerClient::SetInitialNetworkState(std::string type_arg,
std::string state_arg) { std::string state_arg) {
std::string state; std::string state;
state_arg = base::StringToLowerASCII(state_arg);
if (state_arg.empty() || state_arg == "1" || state_arg == "on" || if (state_arg.empty() || state_arg == "1" || state_arg == "on" ||
state_arg == "enabled" || state_arg == "connected" || state_arg == "enabled" || state_arg == "connected" ||
state_arg == "online") { state_arg == "online") {
...@@ -1088,12 +1101,20 @@ bool FakeShillManagerClient::SetInitialNetworkState(std::string type_arg, ...@@ -1088,12 +1101,20 @@ bool FakeShillManagerClient::SetInitialNetworkState(std::string type_arg,
} else if (state_arg == "active" || state_arg == "activated") { } else if (state_arg == "active" || state_arg == "activated") {
// Technology is enabled, a service is connected and Activated. // Technology is enabled, a service is connected and Activated.
state = kNetworkActivated; 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 { } else {
LOG(ERROR) << "Unrecognized initial state: " << state_arg; LOG(ERROR) << "Unrecognized initial state: " << type_arg << "="
<< state_arg;
return false; return false;
} }
type_arg = base::StringToLowerASCII(type_arg);
// Special cases // Special cases
if (type_arg == "wireless") { if (type_arg == "wireless") {
shill_initial_state_map_[shill::kTypeWifi] = state; shill_initial_state_map_[shill::kTypeWifi] = state;
......
...@@ -142,6 +142,9 @@ class CHROMEOS_EXPORT FakeShillManagerClient ...@@ -142,6 +142,9 @@ class CHROMEOS_EXPORT FakeShillManagerClient
// Initial state for fake services. // Initial state for fake services.
std::map<std::string, std::string> shill_initial_state_map_; 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. // Roaming state for fake cellular service.
std::string roaming_state_; std::string roaming_state_;
......
...@@ -4,8 +4,10 @@ ...@@ -4,8 +4,10 @@
:host { :host {
display: inline-block; display: inline-block;
height: 50px;
overflow: hidden; overflow: hidden;
position: relative; position: relative;
width: 50px;
} }
#icon { #icon {
...@@ -38,10 +40,39 @@ ...@@ -38,10 +40,39 @@
top: -400%; 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 { #secure {
height: 40%; height: 40%;
margin-left: 60%; left: 60%;
margin-top: 60%;
position: absolute; position: absolute;
top: 60%;
width: 40%; width: 40%;
} }
...@@ -3,9 +3,15 @@ ...@@ -3,9 +3,15 @@
<polymer-element name="cr-network-icon"> <polymer-element name="cr-network-icon">
<template> <template>
<link rel="stylesheet" href="cr_network_icon.css"> <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" <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> </template>
<script src="cr_network_icon.js"></script> <script src="cr_network_icon.js"></script>
</polymer-element> </polymer-element>
...@@ -10,10 +10,8 @@ ...@@ -10,10 +10,8 @@
(function() { (function() {
/** /**
* @typedef {{ * @typedef {{
* showBadges: boolean,
* showDisconnected: boolean, * showDisconnected: boolean,
* iconType: string,
* connected: boolean,
* secure: boolean,
* strength: number * strength: number
* }} * }}
*/ */
...@@ -51,6 +49,30 @@ function getIconTypeFromNetworkType(networkType) { ...@@ -51,6 +49,30 @@ function getIconTypeFromNetworkType(networkType) {
* @element cr-network-icon * @element cr-network-icon
*/ */
Polymer('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: { publish: {
/** /**
* If set, the ONC data properties will be used to display the icon. * If set, the ONC data properties will be used to display the icon.
...@@ -85,9 +107,7 @@ Polymer('cr-network-icon', { ...@@ -85,9 +107,7 @@ Polymer('cr-network-icon', {
/** @override */ /** @override */
attached: function() { attached: function() {
var params = /** @type {IconParams} */ { var params = /** @type {IconParams} */ {
connected: false, showBadges: false,
iconType: 'ethernet',
secure: false,
showDisconnected: true, showDisconnected: true,
strength: 0, strength: 0,
}; };
...@@ -99,12 +119,9 @@ Polymer('cr-network-icon', { ...@@ -99,12 +119,9 @@ Polymer('cr-network-icon', {
* network state. * network state.
*/ */
networkStateChanged: function() { networkStateChanged: function() {
var iconType = getIconTypeFromNetworkType(this.networkState.data.Type); this.iconType = getIconTypeFromNetworkType(this.networkState.data.Type);
var params = /** @type {IconParams} */ { var params = /** @type {IconParams} */ {
connected: this.networkState.data.ConnectionState == 'Connected', showBadges: true,
iconType: iconType,
secure: iconType == 'wifi' &&
this.networkState.getWiFiSecurity() != 'None',
showDisconnected: !this.isListItem, showDisconnected: !this.isListItem,
strength: this.networkState.getStrength(), strength: this.networkState.getStrength(),
}; };
...@@ -116,16 +133,33 @@ Polymer('cr-network-icon', { ...@@ -116,16 +133,33 @@ Polymer('cr-network-icon', {
* of network, showing a disconnected icon where appropriate and no badges. * of network, showing a disconnected icon where appropriate and no badges.
*/ */
networkTypeChanged: function() { networkTypeChanged: function() {
this.iconType = getIconTypeFromNetworkType(this.networkType);
var params = /** @type {IconParams} */ { var params = /** @type {IconParams} */ {
connected: false, showBadges: false,
iconType: getIconTypeFromNetworkType(this.networkType),
secure: false,
showDisconnected: true, showDisconnected: true,
strength: 0, strength: 0,
}; };
this.setIcon_(params); 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|. * Sets the icon and badge based on the current state and |strength|.
* @param {!IconParams} params The set of params describing the icon. * @param {!IconParams} params The set of params describing the icon.
...@@ -133,26 +167,102 @@ Polymer('cr-network-icon', { ...@@ -133,26 +167,102 @@ Polymer('cr-network-icon', {
*/ */
setIcon_: function(params) { setIcon_: function(params) {
var icon = this.$.icon; var icon = this.$.icon;
if (params.iconType)
icon.src = RESOURCE_IMAGE_BASE + params.iconType + RESOURCE_IMAGE_EXT; var multiLevel = (this.iconType == 'wifi' || this.iconType == 'mobile');
var multiLevel, strength; if (this.networkState && multiLevel) {
if (params.iconType == 'wifi' || params.iconType == 'mobile') { this.setMultiLevelIcon_(params);
multiLevel = true;
strength = (params.showDisconnected && !params.connected) ?
-1 : params.strength;
} else { } else {
multiLevel = false; icon.className = multiLevel ? 'multi-level level0' : '';
strength = -1; }
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('level0', strength < 0);
icon.classList.toggle('level1', strength >= 0 && strength <= 25); icon.classList.toggle('level1', strength >= 0 && strength <= 25);
icon.classList.toggle('level2', strength > 25 && strength <= 50); icon.classList.toggle('level2', strength > 25 && strength <= 50);
icon.classList.toggle('level3', strength > 50 && strength <= 75); icon.classList.toggle('level3', strength > 50 && strength <= 75);
icon.classList.toggle('level4', 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', { ...@@ -22,13 +22,22 @@ Polymer('cr-onc-data', {
data: null, data: null,
}, },
/** @override */
created: function() { created: function() {
this.data = /** @type {CrOnc.NetworkConfigType} */({}); this.data = /** @type {CrOnc.NetworkConfigType} */({});
}, },
/** /** @return {boolean} True if the network is connected. */
* @return {number} The signal strength of the network. 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() { getStrength: function() {
var type = this.data.Type; var type = this.data.Type;
var strength = 0; var strength = 0;
...@@ -41,12 +50,21 @@ Polymer('cr-onc-data', { ...@@ -41,12 +50,21 @@ Polymer('cr-onc-data', {
return strength; return strength;
}, },
/** /** @return {CrOnc.Security} The ONC security type. */
* Returns the WiFi security type. Undefined or empty defaults to 'None'.
* @return {string} The WiFi security type.
*/
getWiFiSecurity: function() { getWiFiSecurity: function() {
return (this.data.WiFi && this.data.WiFi.Security) ? 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 @@ ...@@ -12,16 +12,67 @@
var CrOnc = {}; 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} */ /** @typedef {string|!Object} */
CrOnc.ManagedStringType; CrOnc.ManagedStringType;
/** /**
* @typedef {{NetworkTechnology: string, Strength: number}} * @typedef {{
* NetworkTechnology: CrOnc.NetworkTechnology,
* RoamingState: CrOnc.RoamingState,
* Strength: number
* }}
*/ */
CrOnc.CellularType; CrOnc.CellularType;
/** /**
* @typedef {{Security: string, Strength: number}} * @typedef {{Security: CrOnc.Security, Strength: number}}
*/ */
CrOnc.WiFiType; CrOnc.WiFiType;
...@@ -30,22 +81,13 @@ CrOnc.WiFiType; ...@@ -30,22 +81,13 @@ CrOnc.WiFiType;
*/ */
CrOnc.WiMAXType; CrOnc.WiMAXType;
/** @enum {string} */
CrOnc.Type = {
CELLULAR: "Cellular",
ETHERNET: "Ethernet",
VPN: "VPN",
WIFI: "WiFi",
WIMAX: "WiMAX",
};
/** /**
* @typedef {{ * @typedef {{
* Cellular: CrOnc.CellularType, * Cellular: CrOnc.CellularType,
* ConnectionState: string, * ConnectionState: CrOnc.ConnectionState,
* GUID: string, * GUID: string,
* Name: CrOnc.ManagedStringType, * Name: CrOnc.ManagedStringType,
* Type: string, * Type: CrOnc.Type,
* WiFi: CrOnc.WiFiType, * WiFi: CrOnc.WiFiType,
* WiMAX: CrOnc.WiMAXType * WiMAX: CrOnc.WiMAXType
* }} * }}
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<grit-part> <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" <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_ETHERNET"
file="cr_elements/cr_network_icon/ethernet.png" file="cr_elements/cr_network_icon/ethernet.png"
type="BINDATA" /> 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" <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_MOBILE"
file="cr_elements/cr_network_icon/mobile.png" file="cr_elements/cr_network_icon/mobile.png"
type="BINDATA" /> type="BINDATA" />
<include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_VPN" <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_VPN"
file="cr_elements/cr_network_icon/vpn.png" file="cr_elements/cr_network_icon/vpn.png"
type="BINDATA" /> type="BINDATA" />
<include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_SECURE" <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_WIFI"
file="cr_elements/cr_network_icon/secure.png" file="cr_elements/cr_network_icon/wifi.png"
type="BINDATA" /> type="BINDATA" />
</grit-part> </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