Commit 2b90791f authored by mnissler@chromium.org's avatar mnissler@chromium.org

Disable UI in chrome://settings/internet and details popup for policy-managed networks.

BUG=chromium-os:23124
TEST=Network configuration continues to work, options are locked down for policy-configured networks.


Review URL: http://codereview.chromium.org/8726007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@112507 0039d316-1c4b-4281-b951-d872f2087c98
parent ef6b8ae9
...@@ -11904,6 +11904,9 @@ Keep your key file in a safe place. You will need it to create new versions of y ...@@ -11904,6 +11904,9 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_OPTIONS_SETTINGS_JOIN_VPN" desc="The title for the dialog to join a VPN."> <message name="IDS_OPTIONS_SETTINGS_JOIN_VPN" desc="The title for the dialog to join a VPN.">
Join private network Join private network
</message> </message>
<message name="IDS_OPTIONS_SETTINGS_MANAGED_NETWORK" desc="Help text to show in the bubble shown on click of the controlled setting indicator on the internet settings page.">
This network is configured by your administrator.
</message>
<message name="IDS_OPTIONS_SETTINGS_USE_SHARED_PROXIES" desc="In the settings tab, the text next to the checkbox for allowing proxy settings for shared networks."> <message name="IDS_OPTIONS_SETTINGS_USE_SHARED_PROXIES" desc="In the settings tab, the text next to the checkbox for allowing proxy settings for shared networks.">
Allow proxies for shared networks Allow proxies for shared networks
</message> </message>
......
...@@ -61,6 +61,8 @@ ...@@ -61,6 +61,8 @@
<input id="preferNetworkWifi" type="checkbox"> <input id="preferNetworkWifi" type="checkbox">
<span i18n-content="inetPreferredNetwork"></span> <span i18n-content="inetPreferredNetwork"></span>
</label> </label>
<span class="controlled-setting-indicator" data="preferred"
for="preferNetworkWifi"></span>
</div> </div>
</td> </td>
</tr> </tr>
...@@ -71,6 +73,8 @@ ...@@ -71,6 +73,8 @@
<input id="autoConnectNetworkWifi" type="checkbox"> <input id="autoConnectNetworkWifi" type="checkbox">
<span i18n-content="inetAutoConnectNetwork"></span> <span i18n-content="inetAutoConnectNetwork"></span>
</label> </label>
<span class="controlled-setting-indicator" data="autoConnect"
for="autoConnectNetworkWifi"></span>
</div> </div>
</td> </td>
</tr> </tr>
...@@ -180,6 +184,8 @@ ...@@ -180,6 +184,8 @@
<option value="-1" i18n-content="cellularApnOther"> <option value="-1" i18n-content="cellularApnOther">
</option> </option>
</select> </select>
<span class="controlled-setting-indicator" data="providerApnList"
for="selectApn"></span>
</td> </td>
</tr> </tr>
<tr class="gsm-only apn-details-view"> <tr class="gsm-only apn-details-view">
...@@ -218,6 +224,8 @@ ...@@ -218,6 +224,8 @@
<input id="autoConnectNetworkCellular" type="checkbox"> <input id="autoConnectNetworkCellular" type="checkbox">
<span i18n-content="inetAutoConnectNetwork"></span> <span i18n-content="inetAutoConnectNetwork"></span>
</label> </label>
<span class="controlled-setting-indicator" data="autoConnect"
for="autoConnectNetworkCellular"></span>
</div> </div>
</td> </td>
</tr> </tr>
...@@ -294,12 +302,16 @@ ...@@ -294,12 +302,16 @@
<input type="radio" name="iptype" id="ipTypeDHCP" value="1"> <input type="radio" name="iptype" id="ipTypeDHCP" value="1">
<span i18n-content="useDHCP"></span> <span i18n-content="useDHCP"></span>
</label> </label>
<span class="controlled-setting-indicator" data="ipconfigDHCP"
for="ipTypeDHCP"></span>
</div> </div>
<div id="ipTypeStaticDiv" class="radio"> <div id="ipTypeStaticDiv" class="radio">
<label> <label>
<input type="radio" name="iptype" id="ipTypeStatic" value="0"> <input type="radio" name="iptype" id="ipTypeStatic" value="0">
<span i18n-content="useStaticIP"></span> <span i18n-content="useStaticIP"></span>
</label> </label>
<span class="controlled-setting-indicator" data="ipconfigStatic"
for="ipTypeStatic"></span>
</div> </div>
<div class="suboption"> <div class="suboption">
<div id="ipConfigManagement" class="settings-list"> <div id="ipConfigManagement" class="settings-list">
...@@ -320,15 +332,19 @@ ...@@ -320,15 +332,19 @@
<div id="cellular-security-options"> <div id="cellular-security-options">
<section> <section>
<div id="sim-pin-lock" class="checkbox"> <div id="sim-pin-lock" class="checkbox">
<label> <label>
<input id="sim-card-lock-enabled" type="checkbox"> <input id="sim-card-lock-enabled" type="checkbox">
<span i18n-content="lockSimCard"></span> <span i18n-content="lockSimCard"></span>
</label> </label>
<span class="controlled-setting-indicator" data="simCardLockEnabled"
for="sim-card-lock-enabled"></span>
</div> </div>
</section> </section>
<section> <section>
<div id="change-pin-area"> <div id="change-pin-area">
<button id="change-pin" i18n-content="changePinButton"></button> <button id="change-pin" i18n-content="changePinButton"></button>
<span class="controlled-setting-indicator" data="simCardLockEnabled"
for="change-pin"></span>
</div> </div>
</section> </section>
</div> </div>
......
...@@ -27,6 +27,10 @@ cr.define('options.internet', function() { ...@@ -27,6 +27,10 @@ cr.define('options.internet', function() {
Constants.TYPE_BLUETOOTH = 4; Constants.TYPE_BLUETOOTH = 4;
Constants.TYPE_CELLULAR = 5; Constants.TYPE_CELLULAR = 5;
Constants.TYPE_VPN = 6; Constants.TYPE_VPN = 6;
// ONC sources:
Constants.ONC_SOURCE_USER_IMPORT = 1;
Constants.ONC_SOURCE_DEVICE_POLICY = 2;
Constants.ONC_SOURCE_USER_POLICY = 3;
/** /**
* Creates a new network list div. * Creates a new network list div.
...@@ -138,6 +142,19 @@ cr.define('options.internet', function() { ...@@ -138,6 +142,19 @@ cr.define('options.internet', function() {
this.connecting = this.data.connecting; this.connecting = this.data.connecting;
this.other = this.data.servicePath == '?'; this.other = this.data.servicePath == '?';
this.id = this.data.servicePath; this.id = this.data.servicePath;
// Insert a div holding the policy-managed indicator.
var policyIndicator = this.ownerDocument.createElement('div');
policyIndicator.className = 'controlled-setting-indicator';
cr.ui.decorate(policyIndicator, options.ControlledSettingIndicator);
if (this.data.policyManaged) {
policyIndicator.controlledBy = 'policy';
policyIndicator.setAttribute('textPolicy',
localStrings.getString('managedNetwork'));
}
this.appendChild(policyIndicator);
// textDiv holds icon, name and status text. // textDiv holds icon, name and status text.
var textDiv = this.ownerDocument.createElement('div'); var textDiv = this.ownerDocument.createElement('div');
textDiv.className = 'network-item-text'; textDiv.className = 'network-item-text';
...@@ -246,7 +263,7 @@ cr.define('options.internet', function() { ...@@ -246,7 +263,7 @@ cr.define('options.internet', function() {
self.data.servicePath, self.data.servicePath,
'forget']); 'forget']);
}); });
button.disabled = this.data.policyManaged;
buttonsDiv.appendChild(button); buttonsDiv.appendChild(button);
} }
this.appendChild(buttonsDiv); this.appendChild(buttonsDiv);
......
<div id="internetPage" class="page" hidden> <div id="internetPage" class="page hide-indicators" hidden>
<h1 i18n-content="internetPage"></h1> <h1 i18n-content="internetPage"></h1>
<div id="locked-network-banner" hidden> <div id="locked-network-banner" hidden>
<span id="locked-network-icon"></span> <span id="locked-network-icon"></span>
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
.network-item { .network-item {
-webkit-box-align: center; -webkit-box-align: center;
-webkit-padding-start: 30px; -webkit-padding-start: 10px;
border: 1px solid rgba(255,255,255,0); /* transparent white */ border: 1px solid rgba(255,255,255,0); /* transparent white */
border-radius: 2px; border-radius: 2px;
display: -webkit-box; display: -webkit-box;
...@@ -55,6 +55,15 @@ ...@@ -55,6 +55,15 @@
border-color: hsl(214, 91%, 85%); border-color: hsl(214, 91%, 85%);
} }
.network-item > .controlled-setting-indicator {
-webkit-margin-end: 5px;
width: 16px;
}
.hide-indicators .network-item > .controlled-setting-indicator {
display: none;
}
.network-item-text { .network-item-text {
-webkit-padding-start: 30px; -webkit-padding-start: 30px;
background: left center no-repeat; background: left center no-repeat;
......
...@@ -71,6 +71,7 @@ const char kNetworkInfoKeyNetworkStatus[] = "networkStatus"; ...@@ -71,6 +71,7 @@ const char kNetworkInfoKeyNetworkStatus[] = "networkStatus";
const char kNetworkInfoKeyNetworkType[] = "networkType"; const char kNetworkInfoKeyNetworkType[] = "networkType";
const char kNetworkInfoKeyRemembered[] = "remembered"; const char kNetworkInfoKeyRemembered[] = "remembered";
const char kNetworkInfoKeyServicePath[] = "servicePath"; const char kNetworkInfoKeyServicePath[] = "servicePath";
const char kNetworkInfoKeyPolicyManaged[] = "policyManaged";
// A helper class for building network information dictionaries to be sent to // A helper class for building network information dictionaries to be sent to
// the webui code. // the webui code.
...@@ -124,6 +125,9 @@ class NetworkInfoDictionary { ...@@ -124,6 +125,9 @@ class NetworkInfoDictionary {
void set_needs_new_plan(bool needs_new_plan) { void set_needs_new_plan(bool needs_new_plan) {
needs_new_plan_ = needs_new_plan; needs_new_plan_ = needs_new_plan;
} }
void set_policy_managed(bool policy_managed) {
policy_managed_ = policy_managed;
}
// Builds the DictionaryValue representation from the previously set // Builds the DictionaryValue representation from the previously set
// parameters. Ownership of the returned pointer is transferred to the caller. // parameters. Ownership of the returned pointer is transferred to the caller.
...@@ -142,6 +146,7 @@ class NetworkInfoDictionary { ...@@ -142,6 +146,7 @@ class NetworkInfoDictionary {
bool shared_; bool shared_;
chromeos::ActivationState activation_state_; chromeos::ActivationState activation_state_;
bool needs_new_plan_; bool needs_new_plan_;
bool policy_managed_;
DISALLOW_COPY_AND_ASSIGN(NetworkInfoDictionary); DISALLOW_COPY_AND_ASSIGN(NetworkInfoDictionary);
}; };
...@@ -154,6 +159,7 @@ NetworkInfoDictionary::NetworkInfoDictionary() { ...@@ -154,6 +159,7 @@ NetworkInfoDictionary::NetworkInfoDictionary() {
set_shared(false); set_shared(false);
set_activation_state(chromeos::ACTIVATION_STATE_UNKNOWN); set_activation_state(chromeos::ACTIVATION_STATE_UNKNOWN);
set_needs_new_plan(false); set_needs_new_plan(false);
set_policy_managed(false);
} }
NetworkInfoDictionary::NetworkInfoDictionary(const chromeos::Network* network) { NetworkInfoDictionary::NetworkInfoDictionary(const chromeos::Network* network) {
...@@ -167,6 +173,7 @@ NetworkInfoDictionary::NetworkInfoDictionary(const chromeos::Network* network) { ...@@ -167,6 +173,7 @@ NetworkInfoDictionary::NetworkInfoDictionary(const chromeos::Network* network) {
set_remembered(false); set_remembered(false);
set_shared(false); set_shared(false);
set_needs_new_plan(false); set_needs_new_plan(false);
set_policy_managed(chromeos::NetworkUIData::IsManaged(network));
} }
NetworkInfoDictionary::NetworkInfoDictionary( NetworkInfoDictionary::NetworkInfoDictionary(
...@@ -183,6 +190,8 @@ NetworkInfoDictionary::NetworkInfoDictionary( ...@@ -183,6 +190,8 @@ NetworkInfoDictionary::NetworkInfoDictionary(
set_remembered(true); set_remembered(true);
set_shared(remembered->profile_type() == chromeos::PROFILE_SHARED); set_shared(remembered->profile_type() == chromeos::PROFILE_SHARED);
set_needs_new_plan(false); set_needs_new_plan(false);
set_policy_managed(
network ? chromeos::NetworkUIData::IsManaged(network) : false);
} }
DictionaryValue* NetworkInfoDictionary::BuildDictionary() { DictionaryValue* NetworkInfoDictionary::BuildDictionary() {
...@@ -228,6 +237,7 @@ DictionaryValue* NetworkInfoDictionary::BuildDictionary() { ...@@ -228,6 +237,7 @@ DictionaryValue* NetworkInfoDictionary::BuildDictionary() {
static_cast<int>(connection_type_)); static_cast<int>(connection_type_));
network_info->SetBoolean(kNetworkInfoKeyRemembered, remembered_); network_info->SetBoolean(kNetworkInfoKeyRemembered, remembered_);
network_info->SetString(kNetworkInfoKeyServicePath, service_path_); network_info->SetString(kNetworkInfoKeyServicePath, service_path_);
network_info->SetBoolean(kNetworkInfoKeyPolicyManaged, policy_managed_);
return network_info.release(); return network_info.release();
} }
...@@ -298,6 +308,9 @@ void InternetOptionsHandler::GetLocalizedValues( ...@@ -298,6 +308,9 @@ void InternetOptionsHandler::GetLocalizedValues(
l10n_util::GetStringUTF16( l10n_util::GetStringUTF16(
IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CHANGE_PROXY_BUTTON)); IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CHANGE_PROXY_BUTTON));
localized_strings->SetString("managedNetwork",
l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_MANAGED_NETWORK));
localized_strings->SetString("wifiNetworkTabLabel", localized_strings->SetString("wifiNetworkTabLabel",
l10n_util::GetStringUTF16( l10n_util::GetStringUTF16(
IDS_OPTIONS_SETTINGS_INTERNET_TAB_WIFI)); IDS_OPTIONS_SETTINGS_INTERNET_TAB_WIFI));
...@@ -883,6 +896,9 @@ void InternetOptionsHandler::PopulateDictionaryDetails( ...@@ -883,6 +896,9 @@ void InternetOptionsHandler::PopulateDictionaryDetails(
chromeos::NetworkLibrary::FORMAT_COLON_SEPARATED_HEX); chromeos::NetworkLibrary::FORMAT_COLON_SEPARATED_HEX);
if (!hardware_address.empty()) if (!hardware_address.empty())
dictionary.SetString("hardwareAddress", hardware_address); dictionary.SetString("hardwareAddress", hardware_address);
scoped_ptr<DictionaryValue> ipconfig_dhcp;
scoped_ptr<DictionaryValue> ipconfig_static;
for (chromeos::NetworkIPConfigVector::const_iterator it = ipconfigs.begin(); for (chromeos::NetworkIPConfigVector::const_iterator it = ipconfigs.begin();
it != ipconfigs.end(); ++it) { it != ipconfigs.end(); ++it) {
const chromeos::NetworkIPConfig& ipconfig = *it; const chromeos::NetworkIPConfig& ipconfig = *it;
...@@ -892,11 +908,18 @@ void InternetOptionsHandler::PopulateDictionaryDetails( ...@@ -892,11 +908,18 @@ void InternetOptionsHandler::PopulateDictionaryDetails(
ipconfig_dict->SetString("gateway", ipconfig.gateway); ipconfig_dict->SetString("gateway", ipconfig.gateway);
ipconfig_dict->SetString("dns", ipconfig.name_servers); ipconfig_dict->SetString("dns", ipconfig.name_servers);
if (ipconfig.type == chromeos::IPCONFIG_TYPE_DHCP) if (ipconfig.type == chromeos::IPCONFIG_TYPE_DHCP)
dictionary.Set("ipconfigDHCP", ipconfig_dict.release()); ipconfig_dhcp.reset(ipconfig_dict.release());
else if (ipconfig.type == chromeos::IPCONFIG_TYPE_IPV4) else if (ipconfig.type == chromeos::IPCONFIG_TYPE_IPV4)
dictionary.Set("ipconfigStatic", ipconfig_dict.release()); ipconfig_static.reset(ipconfig_dict.release());
} }
chromeos::NetworkPropertyUIData ipconfig_dhcp_ui_data(network, NULL);
SetValueDictionary(&dictionary, "ipconfigDHCP", ipconfig_dhcp.release(),
ipconfig_dhcp_ui_data);
chromeos::NetworkPropertyUIData ipconfig_static_ui_data(network, NULL);
SetValueDictionary(&dictionary, "ipconfigStatic", ipconfig_static.release(),
ipconfig_static_ui_data);
chromeos::ConnectionType type = network->type(); chromeos::ConnectionType type = network->type();
dictionary.SetInteger("type", type); dictionary.SetInteger("type", type);
dictionary.SetString("servicePath", network->service_path()); dictionary.SetString("servicePath", network->service_path());
...@@ -914,14 +937,24 @@ void InternetOptionsHandler::PopulateDictionaryDetails( ...@@ -914,14 +937,24 @@ void InternetOptionsHandler::PopulateDictionaryDetails(
dictionary.SetBoolean("showStaticIPConfig", staticIPConfig && dictionary.SetBoolean("showStaticIPConfig", staticIPConfig &&
(type == chromeos::TYPE_WIFI || type == chromeos::TYPE_ETHERNET)); (type == chromeos::TYPE_WIFI || type == chromeos::TYPE_ETHERNET));
chromeos::NetworkPropertyUIData preferred_ui_data(
network, chromeos::NetworkUIData::kPropertyPreferred);
if (network_profile == chromeos::PROFILE_USER) { if (network_profile == chromeos::PROFILE_USER) {
dictionary.SetBoolean("showPreferred", true); dictionary.SetBoolean("showPreferred", true);
dictionary.SetBoolean("preferred", network->preferred()); SetValueDictionary(&dictionary, "preferred",
Value::CreateBooleanValue(network->preferred()),
preferred_ui_data);
} else { } else {
dictionary.SetBoolean("showPreferred", false); dictionary.SetBoolean("showPreferred", false);
dictionary.SetBoolean("preferred", false); SetValueDictionary(&dictionary, "preferred",
Value::CreateBooleanValue(network->preferred()),
preferred_ui_data);
} }
dictionary.SetBoolean("autoConnect", network->auto_connect()); chromeos::NetworkPropertyUIData auto_connect_ui_data(
network, chromeos::NetworkUIData::kPropertyAutoConnect);
SetValueDictionary(&dictionary, "autoConnect",
Value::CreateBooleanValue(network->auto_connect()),
auto_connect_ui_data);
if (type == chromeos::TYPE_WIFI) { if (type == chromeos::TYPE_WIFI) {
dictionary.SetBoolean("deviceConnected", cros_->wifi_connected()); dictionary.SetBoolean("deviceConnected", cros_->wifi_connected());
...@@ -1014,6 +1047,7 @@ void InternetOptionsHandler::PopulateCellularDetails( ...@@ -1014,6 +1047,7 @@ void InternetOptionsHandler::PopulateCellularDetails(
const chromeos::NetworkDevice* device = const chromeos::NetworkDevice* device =
cros_->FindNetworkDeviceByPath(cellular->device_path()); cros_->FindNetworkDeviceByPath(cellular->device_path());
if (device) { if (device) {
chromeos::NetworkPropertyUIData cellular_propety_ui_data(cellular, NULL);
dictionary->SetString("manufacturer", device->manufacturer()); dictionary->SetString("manufacturer", device->manufacturer());
dictionary->SetString("modelId", device->model_id()); dictionary->SetString("modelId", device->model_id());
dictionary->SetString("firmwareRevision", device->firmware_revision()); dictionary->SetString("firmwareRevision", device->firmware_revision());
...@@ -1028,8 +1062,11 @@ void InternetOptionsHandler::PopulateCellularDetails( ...@@ -1028,8 +1062,11 @@ void InternetOptionsHandler::PopulateCellularDetails(
dictionary->SetString("min", device->min()); dictionary->SetString("min", device->min());
dictionary->SetBoolean("gsm", dictionary->SetBoolean("gsm",
device->technology_family() == chromeos::TECHNOLOGY_FAMILY_GSM); device->technology_family() == chromeos::TECHNOLOGY_FAMILY_GSM);
dictionary->SetBoolean("simCardLockEnabled", SetValueDictionary(
device->sim_pin_required() == chromeos::SIM_PIN_REQUIRED); dictionary, "simCardLockEnabled",
Value::CreateBooleanValue(
device->sim_pin_required() == chromeos::SIM_PIN_REQUIRED),
cellular_propety_ui_data);
chromeos::MobileConfig* config = chromeos::MobileConfig::GetInstance(); chromeos::MobileConfig* config = chromeos::MobileConfig::GetInstance();
if (config->IsReady()) { if (config->IsReady()) {
...@@ -1046,7 +1083,8 @@ void InternetOptionsHandler::PopulateCellularDetails( ...@@ -1046,7 +1083,8 @@ void InternetOptionsHandler::PopulateCellularDetails(
it != apn_list.end(); ++it) { it != apn_list.end(); ++it) {
apn_list_value->Append(CreateDictionaryFromCellularApn(*it)); apn_list_value->Append(CreateDictionaryFromCellularApn(*it));
} }
dictionary->Set("providerApnList", apn_list_value); SetValueDictionary(dictionary, "providerApnList", apn_list_value,
cellular_propety_ui_data);
} }
SetActivationButtonVisibility(cellular, dictionary); SetActivationButtonVisibility(cellular, dictionary);
...@@ -1335,3 +1373,22 @@ void InternetOptionsHandler::FillNetworkInfo(DictionaryValue* dictionary) { ...@@ -1335,3 +1373,22 @@ void InternetOptionsHandler::FillNetworkInfo(DictionaryValue* dictionary) {
dictionary->SetBoolean("cellularBusy", cros_->cellular_busy()); dictionary->SetBoolean("cellularBusy", cros_->cellular_busy());
dictionary->SetBoolean("cellularEnabled", cros_->cellular_enabled()); dictionary->SetBoolean("cellularEnabled", cros_->cellular_enabled());
} }
void InternetOptionsHandler::SetValueDictionary(
DictionaryValue* settings,
const char* key,
base::Value* value,
const chromeos::NetworkPropertyUIData& ui_data) {
DictionaryValue* value_dict = new DictionaryValue();
// DictionaryValue::Set() takes ownership of |value|.
if (value)
value_dict->Set("value", value);
const base::Value* default_value = ui_data.default_value();
if (default_value)
value_dict->Set("default", default_value->DeepCopy());
if (ui_data.managed())
value_dict->SetString("controlledBy", "policy");
else if (ui_data.recommended())
value_dict->SetString("controlledBy", "recommended");
settings->Set(key, value_dict);
}
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "chrome/browser/chromeos/cros/network_library.h" #include "chrome/browser/chromeos/cros/network_library.h"
#include "chrome/browser/chromeos/cros/network_ui_data.h"
#include "chrome/browser/ui/webui/options/options_ui.h" #include "chrome/browser/ui/webui/options/options_ui.h"
#include "content/public/browser/notification_registrar.h" #include "content/public/browser/notification_registrar.h"
#include "ui/gfx/native_widget_types.h" #include "ui/gfx/native_widget_types.h"
...@@ -129,6 +130,14 @@ class InternetOptionsHandler ...@@ -129,6 +130,14 @@ class InternetOptionsHandler
// case of cellular networks, network technology and roaming status. // case of cellular networks, network technology and roaming status.
void MonitorNetworks(); void MonitorNetworks();
// Stores a dictionary under |key| in |settings| that is suitable to be sent
// to the webui that contains the actual value of a setting and whether it's
// controlled by policy. Takes ownership of |value|.
void SetValueDictionary(DictionaryValue* settings,
const char* key,
base::Value* value,
const chromeos::NetworkPropertyUIData& ui_data);
// Convenience pointer to netwrok library (will not change). // Convenience pointer to netwrok library (will not change).
chromeos::NetworkLibrary* cros_; chromeos::NetworkLibrary* cros_;
......
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