Commit 0f0b7d23 authored by Azeem Arshad's avatar Azeem Arshad Committed by Commit Bot

[CrOS Cellular] Store custom APN in pref storage.

This CL addresses issue with "Other" APN values getting
erased when changing APN options. This is fixed by saving
APN value that are not in the APN db to the pref store.
This list is made available in cros_network_config mojo
api as a new custom_apn_list property.

This also fixes issue with "Other" apn text fields getting
overwritten because of managed property changes.

Bug: b/167297672
Change-Id: I0ffb497be6d274eba99835f56c79e2d4a3004639
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2435978
Commit-Queue: Azeem Arshad <azeemarshad@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#812907}
parent ffbe3d53
...@@ -102,6 +102,11 @@ bool DeviceState::PropertyChanged(const std::string& key, ...@@ -102,6 +102,11 @@ bool DeviceState::PropertyChanged(const std::string& key,
return GetStringValue(key, value, &mdn_); return GetStringValue(key, value, &mdn_);
} else if (key == shill::kSIMPresentProperty) { } else if (key == shill::kSIMPresentProperty) {
return GetBooleanValue(key, value, &sim_present_); return GetBooleanValue(key, value, &sim_present_);
} else if (key == shill::kCellularApnListProperty) {
if (!value.is_list())
return false;
apn_list_ = base::ListValue(value.Clone().TakeList());
return true;
} else if (key == shill::kEapAuthenticationCompletedProperty) { } else if (key == shill::kEapAuthenticationCompletedProperty) {
return GetBooleanValue(key, value, &eap_authentication_completed_); return GetBooleanValue(key, value, &eap_authentication_completed_);
} else if (key == shill::kIPConfigsProperty) { } else if (key == shill::kIPConfigsProperty) {
...@@ -169,4 +174,14 @@ bool DeviceState::IsSimLocked() const { ...@@ -169,4 +174,14 @@ bool DeviceState::IsSimLocked() const {
sim_lock_type_ == shill::kSIMLockPuk; sim_lock_type_ == shill::kSIMLockPuk;
} }
bool DeviceState::HasAPN(const std::string& access_point_name) const {
for (const auto& apn : apn_list_.GetList()) {
const std::string* apn_name = apn.FindStringKey(shill::kApnProperty);
if (apn_name && *apn_name == access_point_name) {
return true;
}
}
return false;
}
} // namespace chromeos } // namespace chromeos
...@@ -52,6 +52,7 @@ class COMPONENT_EXPORT(CHROMEOS_NETWORK) DeviceState : public ManagedState { ...@@ -52,6 +52,7 @@ class COMPONENT_EXPORT(CHROMEOS_NETWORK) DeviceState : public ManagedState {
const std::string& imei() const { return imei_; } const std::string& imei() const { return imei_; }
const std::string& iccid() const { return iccid_; } const std::string& iccid() const { return iccid_; }
const std::string& mdn() const { return mdn_; } const std::string& mdn() const { return mdn_; }
const base::ListValue& apn_list() const { return apn_list_; }
const CellularScanResults& scan_results() const { return scan_results_; } const CellularScanResults& scan_results() const { return scan_results_; }
// |ip_configs_| is kept up to date by NetworkStateHandler. // |ip_configs_| is kept up to date by NetworkStateHandler.
...@@ -88,6 +89,9 @@ class COMPONENT_EXPORT(CHROMEOS_NETWORK) DeviceState : public ManagedState { ...@@ -88,6 +89,9 @@ class COMPONENT_EXPORT(CHROMEOS_NETWORK) DeviceState : public ManagedState {
bool IsSimAbsent() const; bool IsSimAbsent() const;
bool IsSimLocked() const; bool IsSimLocked() const;
// Returns true if |access_point_name| exists in apn_list for this device.
bool HasAPN(const std::string& access_point_name) const;
private: private:
// Common Device Properties // Common Device Properties
std::string mac_address_; std::string mac_address_;
...@@ -123,6 +127,9 @@ class COMPONENT_EXPORT(CHROMEOS_NETWORK) DeviceState : public ManagedState { ...@@ -123,6 +127,9 @@ class COMPONENT_EXPORT(CHROMEOS_NETWORK) DeviceState : public ManagedState {
// Keep all Device properties in a dictionary for now. See comment above. // Keep all Device properties in a dictionary for now. See comment above.
base::DictionaryValue properties_; base::DictionaryValue properties_;
// List of APNs.
base::ListValue apn_list_;
// Dictionary of IPConfig properties, keyed by IpConfig path. // Dictionary of IPConfig properties, keyed by IpConfig path.
base::DictionaryValue ip_configs_; base::DictionaryValue ip_configs_;
......
...@@ -29,6 +29,7 @@ const char kIsFromSync[] = "is_from_sync"; ...@@ -29,6 +29,7 @@ const char kIsFromSync[] = "is_from_sync";
const char kOwner[] = "owner"; const char kOwner[] = "owner";
const char kExternalModifications[] = "external_modifications"; const char kExternalModifications[] = "external_modifications";
const char kBadPassword[] = "bad_password"; const char kBadPassword[] = "bad_password";
const char kCustomApnList[] = "custom_apn_list";
std::string GetPath(const std::string& guid, const std::string& subkey) { std::string GetPath(const std::string& guid, const std::string& subkey) {
return base::StringPrintf("%s.%s", guid.c_str(), subkey.c_str()); return base::StringPrintf("%s.%s", guid.c_str(), subkey.c_str());
...@@ -335,6 +336,16 @@ bool NetworkMetadataStore::GetHasBadPassword(const std::string& network_guid) { ...@@ -335,6 +336,16 @@ bool NetworkMetadataStore::GetHasBadPassword(const std::string& network_guid) {
return has_bad_password->GetBool(); return has_bad_password->GetBool();
} }
void NetworkMetadataStore::SetCustomAPNList(const std::string& network_guid,
base::Value list) {
SetPref(network_guid, kCustomApnList, std::move(list));
}
const base::Value* NetworkMetadataStore::GetCustomAPNList(
const std::string& network_guid) {
return GetPref(network_guid, kCustomApnList);
}
void NetworkMetadataStore::SetPref(const std::string& network_guid, void NetworkMetadataStore::SetPref(const std::string& network_guid,
const std::string& key, const std::string& key,
base::Value value) { base::Value value) {
......
...@@ -93,6 +93,14 @@ class COMPONENT_EXPORT(CHROMEOS_NETWORK) NetworkMetadataStore ...@@ -93,6 +93,14 @@ class COMPONENT_EXPORT(CHROMEOS_NETWORK) NetworkMetadataStore
// will always return false. // will always return false.
bool GetHasBadPassword(const std::string& network_guid); bool GetHasBadPassword(const std::string& network_guid);
// Stores a list of user-entered APN entries for a cellular network. Takes
// ownership of |list|.
void SetCustomAPNList(const std::string& network_guid, base::Value list);
// Returns custom apn list for cellular network with given guid. Returns
// nullptr if no pref exists for |network_guid|.
const base::Value* GetCustomAPNList(const std::string& network_guid);
// When the active user is the device owner and its the first login, this // When the active user is the device owner and its the first login, this
// marks networks that were added in OOBE to the user's list. // marks networks that were added in OOBE to the user's list.
void OwnSharedNetworksOnFirstUserLogin(); void OwnSharedNetworksOnFirstUserLogin();
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <vector> #include <vector>
#include "base/optional.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "chromeos/components/sync_wifi/network_eligibility_checker.h" #include "chromeos/components/sync_wifi/network_eligibility_checker.h"
#include "chromeos/login/login_state/login_state.h" #include "chromeos/login/login_state/login_state.h"
...@@ -1268,7 +1269,7 @@ mojom::ManagedPropertiesPtr ManagedPropertiesToMojo( ...@@ -1268,7 +1269,7 @@ mojom::ManagedPropertiesPtr ManagedPropertiesToMojo(
} }
cellular->auto_connect = cellular->auto_connect =
GetManagedBoolean(cellular_dict, ::onc::cellular::kAutoConnect); GetManagedBoolean(cellular_dict, ::onc::cellular::kAutoConnect);
cellular->apn = cellular->selected_apn =
GetManagedApnProperties(cellular_dict, ::onc::cellular::kAPN); GetManagedApnProperties(cellular_dict, ::onc::cellular::kAPN);
cellular->apn_list = cellular->apn_list =
GetManagedApnList(cellular_dict->FindKey(::onc::cellular::kAPNList)); GetManagedApnList(cellular_dict->FindKey(::onc::cellular::kAPNList));
...@@ -1894,6 +1895,15 @@ void CrosNetworkConfig::OnGetManagedProperties( ...@@ -1894,6 +1895,15 @@ void CrosNetworkConfig::OnGetManagedProperties(
mojom::ManagedPropertiesPtr managed_properties = ManagedPropertiesToMojo( mojom::ManagedPropertiesPtr managed_properties = ManagedPropertiesToMojo(
network_state, vpn_providers_, &properties.value()); network_state, vpn_providers_, &properties.value());
if (managed_properties->type == mojom::NetworkType::kCellular) {
std::vector<mojom::ApnPropertiesPtr> custom_apn_list =
GetCustomAPNList(guid);
if (!custom_apn_list.empty()) {
managed_properties->type_properties->get_cellular()->custom_apn_list =
std::move(custom_apn_list);
}
}
// For Ethernet networks with no authentication, check for a separate // For Ethernet networks with no authentication, check for a separate
// EthernetEAP configuration. // EthernetEAP configuration.
const NetworkState* eap_state = nullptr; const NetworkState* eap_state = nullptr;
...@@ -1983,6 +1993,11 @@ void CrosNetworkConfig::SetProperties(const std::string& guid, ...@@ -1983,6 +1993,11 @@ void CrosNetworkConfig::SetProperties(const std::string& guid,
network = eap_state; network = eap_state;
} }
if (network->type() == shill::kTypeCellular &&
properties->type_config->is_cellular()) {
UpdateCustomAPNList(network, properties.get());
}
std::unique_ptr<base::DictionaryValue> onc = std::unique_ptr<base::DictionaryValue> onc =
GetOncFromConfigProperties(properties.get(), guid); GetOncFromConfigProperties(properties.get(), guid);
if (!onc) { if (!onc) {
...@@ -2335,6 +2350,78 @@ void CrosNetworkConfig::SelectCellularMobileNetworkFailure( ...@@ -2335,6 +2350,78 @@ void CrosNetworkConfig::SelectCellularMobileNetworkFailure(
select_cellular_mobile_network_callbacks_.erase(iter); select_cellular_mobile_network_callbacks_.erase(iter);
} }
void CrosNetworkConfig::UpdateCustomAPNList(
const NetworkState* network,
const mojom::ConfigProperties* properties) {
const mojom::CellularConfigProperties& cellular_config =
*properties->type_config->get_cellular();
if (!cellular_config.apn) {
return;
}
const DeviceState* device =
network_state_handler_->GetDeviceState(network->device_path());
DCHECK(device);
// Do not update custom APN list if APN is in device APN list.
if (device->HasAPN(cellular_config.apn->access_point_name)) {
return;
}
base::Value custom_apn(base::Value::Type::DICTIONARY);
custom_apn.SetStringKey(::onc::cellular_apn::kAccessPointName,
cellular_config.apn->access_point_name);
SetString(::onc::cellular_apn::kName, cellular_config.apn->name, &custom_apn);
SetString(::onc::cellular_apn::kUsername, cellular_config.apn->username,
&custom_apn);
SetString(::onc::cellular_apn::kPassword, cellular_config.apn->password,
&custom_apn);
SetString(::onc::cellular_apn::kAuthentication,
cellular_config.apn->authentication, &custom_apn);
SetString(::onc::cellular_apn::kLocalizedName,
cellular_config.apn->localized_name, &custom_apn);
SetString(::onc::cellular_apn::kLanguage, cellular_config.apn->language,
&custom_apn);
// The UI currently only supports setting a single custom apn.
base::Value custom_apn_list(base::Value::Type::LIST);
custom_apn_list.Append(std::move(custom_apn));
NET_LOG(DEBUG) << "Saving Custom APN entry for " << network->guid();
NetworkMetadataStore* network_metadata_store =
NetworkHandler::Get()->network_metadata_store();
network_metadata_store->SetCustomAPNList(network->guid(),
std::move(custom_apn_list));
}
std::vector<mojom::ApnPropertiesPtr> CrosNetworkConfig::GetCustomAPNList(
const std::string& guid) {
NetworkMetadataStore* network_metadata_store =
NetworkHandler::Get()->network_metadata_store();
std::vector<mojom::ApnPropertiesPtr> mojo_custom_apns;
const base::Value* custom_apn_list =
network_metadata_store->GetCustomAPNList(guid);
if (!custom_apn_list) {
return mojo_custom_apns;
}
DCHECK(custom_apn_list->is_list());
for (const auto& apn : custom_apn_list->GetList()) {
DCHECK(apn.is_dict());
mojom::ApnPropertiesPtr mojo_apn = mojom::ApnProperties::New();
mojo_apn->access_point_name =
GetRequiredString(&apn, ::onc::cellular_apn::kAccessPointName);
mojo_apn->name = GetString(&apn, ::onc::cellular_apn::kName);
mojo_apn->username = GetString(&apn, ::onc::cellular_apn::kUsername);
mojo_apn->password = GetString(&apn, ::onc::cellular_apn::kPassword);
mojo_apn->authentication =
GetString(&apn, ::onc::cellular_apn::kAuthentication);
mojo_apn->localized_name =
GetString(&apn, ::onc::cellular_apn::kLocalizedName);
mojo_apn->language = GetString(&apn, ::onc::cellular_apn::kLanguage);
mojo_custom_apns.push_back(std::move(mojo_apn));
}
return mojo_custom_apns;
}
void CrosNetworkConfig::RequestNetworkScan(mojom::NetworkType type) { void CrosNetworkConfig::RequestNetworkScan(mojom::NetworkType type) {
network_state_handler_->RequestScan(MojoTypeToPattern(type)); network_state_handler_->RequestScan(MojoTypeToPattern(type));
} }
......
...@@ -127,6 +127,10 @@ class CrosNetworkConfig : public mojom::CrosNetworkConfig, ...@@ -127,6 +127,10 @@ class CrosNetworkConfig : public mojom::CrosNetworkConfig,
int callback_id, int callback_id,
const std::string& error_name, const std::string& error_name,
std::unique_ptr<base::DictionaryValue> error_data); std::unique_ptr<base::DictionaryValue> error_data);
void UpdateCustomAPNList(const NetworkState* network,
const mojom::ConfigProperties* properties);
std::vector<mojom::ApnPropertiesPtr> GetCustomAPNList(
const std::string& guid);
void StartConnectSuccess(int callback_id); void StartConnectSuccess(int callback_id);
void StartConnectFailure(int callback_id, void StartConnectFailure(int callback_id,
......
...@@ -43,7 +43,22 @@ namespace network_config { ...@@ -43,7 +43,22 @@ namespace network_config {
namespace { namespace {
const int kSimRetriesLeft = 3; const int kSimRetriesLeft = 3;
const char* kCellularDevicePath = "/device/stub_cellular_device"; const char kCellularDevicePath[] = "/device/stub_cellular_device";
const char kCellularTestApn1[] = "TEST.APN1";
const char kCellularTestApnName1[] = "Test Apn 1";
const char kCellularTestApnUsername1[] = "Test User";
const char kCellularTestApnPassword1[] = "Test Pass";
const char kCellularTestApn2[] = "TEST.APN2";
const char kCellularTestApnName2[] = "Test Apn 2";
const char kCellularTestApnUsername2[] = "Test User";
const char kCellularTestApnPassword2[] = "Test Pass";
const char kCellularTestApn3[] = "TEST.APN3";
const char kCellularTestApnName3[] = "Test Apn 3";
const char kCellularTestApnUsername3[] = "Test User";
const char kCellularTestApnPassword3[] = "Test Pass";
} // namespace } // namespace
...@@ -164,10 +179,12 @@ class CrosNetworkConfigTest : public testing::Test { ...@@ -164,10 +179,12 @@ class CrosNetworkConfigTest : public testing::Test {
R"({"GUID": "wifi2_guid", "Type": "wifi", "SSID": "wifi2", R"({"GUID": "wifi2_guid", "Type": "wifi", "SSID": "wifi2",
"State": "idle", "SecurityClass": "psk", "Strength": 100, "State": "idle", "SecurityClass": "psk", "Strength": 100,
"Profile": "user_profile_path"})"); "Profile": "user_profile_path"})");
helper().ConfigureService( helper().ConfigureService(base::StringPrintf(
R"({"GUID": "cellular_guid", "Type": "cellular", "State": "idle", R"({"GUID": "cellular_guid", "Type": "cellular", "State": "idle",
"Strength": 0, "Cellular.NetworkTechnology": "LTE", "Strength": 0, "Cellular.NetworkTechnology": "LTE",
"Cellular.ActivationState": "activated"})"); "Cellular.ActivationState": "activated",
"Profile": "%s"})",
NetworkProfileHandler::GetSharedProfilePath().c_str()));
helper().ConfigureService( helper().ConfigureService(
R"({"GUID": "vpn_guid", "Type": "vpn", "State": "association", R"({"GUID": "vpn_guid", "Type": "vpn", "State": "association",
"Provider": {"Type": "l2tpipsec"}})"); "Provider": {"Type": "l2tpipsec"}})");
...@@ -190,6 +207,31 @@ class CrosNetworkConfigTest : public testing::Test { ...@@ -190,6 +207,31 @@ class CrosNetworkConfigTest : public testing::Test {
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
} }
void SetupAPNList() {
base::Value apn_list(base::Value::Type::LIST);
base::Value apn_entry1(base::Value::Type::DICTIONARY);
apn_entry1.SetStringKey(shill::kApnNameProperty, kCellularTestApnName1);
apn_entry1.SetStringKey(shill::kApnProperty, kCellularTestApn1);
apn_entry1.SetStringKey(shill::kApnUsernameProperty,
kCellularTestApnUsername1);
apn_entry1.SetStringKey(shill::kApnPasswordProperty,
kCellularTestApnPassword1);
apn_list.Append(std::move(apn_entry1));
base::Value apn_entry2(base::Value::Type::DICTIONARY);
apn_entry2.SetStringKey(shill::kApnNameProperty, kCellularTestApnName2);
apn_entry2.SetStringKey(shill::kApnProperty, kCellularTestApn2);
apn_entry2.SetStringKey(shill::kApnUsernameProperty,
kCellularTestApnUsername2);
apn_entry2.SetStringKey(shill::kApnPasswordProperty,
kCellularTestApnPassword2);
apn_list.Append(std::move(apn_entry2));
helper().device_test()->SetDeviceProperty(
kCellularDevicePath, shill::kCellularApnListProperty, apn_list,
/*notify_changed=*/true);
base::RunLoop().RunUntilIdle();
}
void SetupEthernetEAP() { void SetupEthernetEAP() {
std::string eap_path = helper().ConfigureService( std::string eap_path = helper().ConfigureService(
R"({"GUID": "eth_eap_guid", "Type": "etherneteap", R"({"GUID": "eth_eap_guid", "Type": "etherneteap",
...@@ -538,7 +580,7 @@ TEST_F(CrosNetworkConfigTest, GetNetworkState) { ...@@ -538,7 +580,7 @@ TEST_F(CrosNetworkConfigTest, GetNetworkState) {
EXPECT_EQ(0, cellular->signal_strength); EXPECT_EQ(0, cellular->signal_strength);
EXPECT_EQ("LTE", cellular->network_technology); EXPECT_EQ("LTE", cellular->network_technology);
EXPECT_EQ(mojom::ActivationStateType::kActivated, cellular->activation_state); EXPECT_EQ(mojom::ActivationStateType::kActivated, cellular->activation_state);
EXPECT_EQ(mojom::OncSource::kNone, network->source); EXPECT_EQ(mojom::OncSource::kDevice, network->source);
EXPECT_TRUE(cellular->sim_locked); EXPECT_TRUE(cellular->sim_locked);
network = GetNetworkState("vpn_guid"); network = GetNetworkState("vpn_guid");
...@@ -844,6 +886,57 @@ TEST_F(CrosNetworkConfigTest, SetProperties) { ...@@ -844,6 +886,57 @@ TEST_F(CrosNetworkConfigTest, SetProperties) {
EXPECT_FALSE(success); EXPECT_FALSE(success);
} }
TEST_F(CrosNetworkConfigTest, CustomAPN) {
SetupAPNList();
const char* kGUID = "cellular_guid";
// Verify that setting APN to an entry that already exists in apn list
// does not update the custom apn list.
auto config = mojom::ConfigProperties::New();
auto cellular_config = mojom::CellularConfigProperties::New();
auto new_apn = mojom::ApnProperties::New();
new_apn->access_point_name = kCellularTestApn1;
new_apn->name = kCellularTestApnName1;
new_apn->username = kCellularTestApnUsername1;
new_apn->password = kCellularTestApnPassword1;
cellular_config->apn = std::move(new_apn);
config->type_config = mojom::NetworkTypeConfigProperties::NewCellular(
std::move(cellular_config));
SetProperties(kGUID, std::move(config));
const base::Value* apn_list =
NetworkHandler::Get()->network_metadata_store()->GetCustomAPNList(kGUID);
ASSERT_FALSE(apn_list);
// Verify that custom APN list is updated properly.
config = mojom::ConfigProperties::New();
cellular_config = mojom::CellularConfigProperties::New();
new_apn = mojom::ApnProperties::New();
new_apn->access_point_name = kCellularTestApn3;
new_apn->name = kCellularTestApnName3;
new_apn->username = kCellularTestApnUsername3;
new_apn->password = kCellularTestApnPassword3;
cellular_config->apn = std::move(new_apn);
config->type_config = mojom::NetworkTypeConfigProperties::NewCellular(
std::move(cellular_config));
SetProperties(kGUID, std::move(config));
apn_list =
NetworkHandler::Get()->network_metadata_store()->GetCustomAPNList(kGUID);
ASSERT_TRUE(apn_list);
ASSERT_TRUE(apn_list->is_list());
// Verify that custom APN list is returned properly in managed properties.
mojom::ManagedPropertiesPtr properties = GetManagedProperties(kGUID);
ASSERT_TRUE(properties);
ASSERT_EQ(kGUID, properties->guid);
ASSERT_TRUE(properties->type_properties->is_cellular());
ASSERT_TRUE(
properties->type_properties->get_cellular()->custom_apn_list.has_value());
ASSERT_EQ(
1u, properties->type_properties->get_cellular()->custom_apn_list->size());
ASSERT_EQ(kCellularTestApn3, properties->type_properties->get_cellular()
->custom_apn_list->front()
->access_point_name);
}
TEST_F(CrosNetworkConfigTest, ConfigureNetwork) { TEST_F(CrosNetworkConfigTest, ConfigureNetwork) {
// Note: shared = false requires a UserManager instance. // Note: shared = false requires a UserManager instance.
bool shared = true; bool shared = true;
......
...@@ -483,8 +483,13 @@ struct ManagedOpenVPNProperties { ...@@ -483,8 +483,13 @@ struct ManagedOpenVPNProperties {
struct ManagedCellularProperties { struct ManagedCellularProperties {
ManagedBoolean? auto_connect; ManagedBoolean? auto_connect;
ManagedApnProperties? apn; // The current user selected APN. This corresponds to APN field
// in ONC.
ManagedApnProperties? selected_apn;
ManagedApnList? apn_list; ManagedApnList? apn_list;
// List of user-entered custom APN entries. Note: This field is not
// part of ONC spec.
array<ApnProperties>? custom_apn_list;
ActivationStateType activation_state; ActivationStateType activation_state;
bool allow_roaming = false; bool allow_roaming = false;
string? esn; string? esn;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
<link rel="import" href="chrome://resources/html/i18n_behavior.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html"> <link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
<link rel="import" href="chrome://resources/cr_elements/md_select_css.html"> <link rel="import" href="chrome://resources/cr_elements/md_select_css.html">
<link rel="import" href="chrome://resources/cr_components/chromeos/network/onc_mojo.html">
<link rel="import" href="network_property_list_mojo.html"> <link rel="import" href="network_property_list_mojo.html">
<link rel="import" href="network_shared_css.html"> <link rel="import" href="network_shared_css.html">
...@@ -28,7 +29,7 @@ ...@@ -28,7 +29,7 @@
</select> </select>
</div> </div>
<template is="dom-if" if="[[showOtherApn_(selectedApn_)]]"> <template is="dom-if" if="[[showOtherApn_(selectedApn_)]]">
<div class="property-box single-column indented"> <div class="property-box single-column indented">
<network-property-list-mojo on-property-change="onOtherApnChange_" <network-property-list-mojo on-property-change="onOtherApnChange_"
fields="[[otherApnFields_]]" property-dict="[[otherApn_]]" fields="[[otherApnFields_]]" property-dict="[[otherApn_]]"
......
...@@ -118,19 +118,62 @@ Polymer({ ...@@ -118,19 +118,62 @@ Polymer({
}, },
/** @private*/ /** @private*/
managedPropertiesChanged_() { getActiveApnFromProperties_(managedProperties) {
const cellular = this.managedProperties.typeProperties.cellular; const cellular = managedProperties.typeProperties.cellular;
/** @type {!chromeos.networkConfig.mojom.ApnProperties|undefined} */ let /** @type {!chromeos.networkConfig.mojom.ApnProperties|undefined} */ let
activeApn; activeApn;
if (cellular.apn) { // We show selectedAPN as the active entry in the select list but it may
activeApn = this.getApnFromManaged_(cellular.apn); // not correspond to the currently "active" APN which is represented by
// lastGoodApn.
if (cellular.selectedApn) {
activeApn = this.getApnFromManaged_(cellular.selectedApn);
} else if (cellular.lastGoodApn && cellular.lastGoodApn.accessPointName) { } else if (cellular.lastGoodApn && cellular.lastGoodApn.accessPointName) {
activeApn = cellular.lastGoodApn; activeApn = cellular.lastGoodApn;
} }
if (activeApn && !activeApn.accessPointName) { if (activeApn && !activeApn.accessPointName) {
activeApn = undefined; activeApn = undefined;
} }
this.setApnSelectList_(activeApn); return activeApn;
},
/** @private*/
shouldUpdateSelectList_(oldManagedProperties) {
if (!oldManagedProperties) {
return true;
}
const newActiveApn =
this.getActiveApnFromProperties_(this.managedProperties);
const oldActiveApn = this.getActiveApnFromProperties_(oldManagedProperties);
if (!OncMojo.apnMatch(newActiveApn, oldActiveApn)) {
return true;
}
const newApnList = this.managedProperties.typeProperties.cellular.apnList;
const oldApnList = oldManagedProperties.typeProperties.cellular.apnList;
if (!OncMojo.apnListMatch(
oldApnList && oldApnList.activeValue,
newApnList && newApnList.activeValue)) {
return true;
}
const newCustomApnList =
this.managedProperties.typeProperties.cellular.customApnList;
const oldCustomApnList =
oldManagedProperties.typeProperties.cellular.customApnList;
if (!OncMojo.apnListMatch(oldCustomApnList, newCustomApnList)) {
return true;
}
return false;
},
/** @private*/
managedPropertiesChanged_(managedProperties, oldManagedProperties) {
if (!this.shouldUpdateSelectList_(oldManagedProperties)) {
return;
}
this.setApnSelectList_(this.getActiveApnFromProperties_(managedProperties));
}, },
/** /**
...@@ -157,15 +200,22 @@ Polymer({ ...@@ -157,15 +200,22 @@ Polymer({
activeApnInList = apnList.find(a => a.name === activeApn.name); activeApnInList = apnList.find(a => a.name === activeApn.name);
} }
// If the active APN is not in the list, copy it to otherApn_. const customApnList =
if (!activeApnInList && activeApn && activeApn.accessPointName) { this.managedProperties.typeProperties.cellular.customApnList;
this.otherApn_ = { let otherApn = this.otherApn_;
accessPointName: activeApn.accessPointName, if (customApnList && customApnList.length) {
name: kOtherAccessPointName, // If custom apn list exists, then use it's first entry as otherApn.
username: activeApn.username, otherApn = customApnList[0];
password: activeApn.password, } else if (!activeApnInList && activeApn && activeApn.accessPointName) {
}; // If the active APN is not in the list, copy it to otherApn.
otherApn = activeApn;
} }
this.otherApn_ = {
accessPointName: otherApn.accessPointName,
name: kOtherAccessPointName,
username: otherApn.username,
password: otherApn.password,
};
apnList.push(this.otherApn_); apnList.push(this.otherApn_);
this.apnSelectList_ = apnList; this.apnSelectList_ = apnList;
......
...@@ -1103,6 +1103,37 @@ ...@@ -1103,6 +1103,37 @@
return a.lockType === b.lockType && a.lockEnabled === b.lockEnabled && return a.lockType === b.lockType && a.lockEnabled === b.lockEnabled &&
a.retriesLeft === b.retriesLeft; a.retriesLeft === b.retriesLeft;
} }
/**
* Returns true if the APN properties match.
* @param {chromeos.networkConfig.mojom.ApnProperties} a
* @param {chromeos.networkConfig.mojom.ApnProperties} b
* @return {boolean}
*/
static apnMatch(a, b) {
if (!a || !b) {
return !!a === !!b;
}
return a.accessPointName === b.accessPointName &&
a.name === b.name && a.username === b.username &&
a.password === b.password;
}
/**
* Returns true if the APN List matches.
* @param {Array<!chromeos.networkConfig.mojom.ApnProperties>|undefined} a
* @param {Array<!chromeos.networkConfig.mojom.ApnProperties>|undefined} b
* @return {boolean}
*/
static apnListMatch(a, b) {
if (!a || !b) {
return !!a === !!b;
}
if (a.length !== b.length) {
return false;
}
return a.every((apn, index) => OncMojo.apnMatch(apn, b[index]));
}
} }
/** @typedef {chromeos.networkConfig.mojom.DeviceStateProperties} */ /** @typedef {chromeos.networkConfig.mojom.DeviceStateProperties} */
......
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