Skip to content

Commit

Permalink
[CrOS settings] add network list to Passpoint details page
Browse files Browse the repository at this point in the history
Adds the list of Wi-Fi networks configured by a subscription to the
Passpoint details page. It also adds the Passpoint subscription
identifier to the Wi-Fi network state to be able to find these networks.

Screenshot: https://screenshot.googleplex.com/BVdW4vVmHW99zVa.png

Bug: b:266151248
Test: chromeos_unittests --gtest_filter="CrosNetworkConfigTest.*"
Test: browser_tests --gtest_filter="OSSettingsPasspointSubpageTest.*"
Change-Id: I971c33427f08ee4a054431e67ca80c614b034b9d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4521345
Reviewed-by: Wes Okuhara <wesokuhara@google.com>
Commit-Queue: Damien Dejean <damiendejean@google.com>
Reviewed-by: Arthur Sonzogni <arthursonzogni@chromium.org>
Reviewed-by: Chad Duffin <chadduffin@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1153723}
  • Loading branch information
Damien Dejean authored and Chromium LUCI CQ committed Jun 6, 2023
1 parent a4f179e commit 272b310
Show file tree
Hide file tree
Showing 12 changed files with 156 additions and 11 deletions.
1 change: 1 addition & 0 deletions ash/webui/common/resources/network/onc_mojo.js
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,7 @@ export class OncMojo {
security: SecurityType.kNone,
signalStrength: 0,
ssid: '',
passpointId: '',
};
break;
default:
Expand Down
3 changes: 3 additions & 0 deletions chrome/app/os_settings_strings.grdp
Original file line number Diff line number Diff line change
Expand Up @@ -3904,6 +3904,9 @@ Press an assigned switch or key to remove assignment.
<message name="IDS_SETTINGS_INTERNET_PASSPOINT_SYSTEM_CA" desc="Text displayed when the subscription relies on system CA certificates for server authentication.">
System CAs
</message>
<message name="IDS_SETTINGS_INTERNET_PASSPOINT_ASSOCIATED_WIFI_NETWORKS" desc="Label for the list of Wi-Fi networks connected using the Passpoint subscription.">
Associated Wi-Fi networks
</message>
<message name="IDS_SETTINGS_INTERNET_PASSPOINT_DOMAINS" desc="Label for the list of domains included in the Passpoint subscription.">
Domains
</message>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
a0367d18862222dc9fd6e8f7d189e37432bb56eb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,21 @@
[[certificateAuthorityName_]]
</div>
</div>
<template is="dom-if" if="[[hasNetworks_(networks_)]]">
<div class="settings-box settings-box-text">
$i18n{passpointAssociatedWifiNetworks}
</div>
<div id="passpointNetworksList" class="list-frame vertical-list">
<template is="dom-repeat" items="[[networks_]]">
<div class="list-item">
<cr-link-row embedded label="[[getNetworkDisplayName_(item)]]"
on-click="onAssociatedNetworkClicked_"
role-description="$i18n{subpageArrowRoleDescription}">
</cr-link-row>
</div>
</template>
</div>
</template>
<cr-expand-button aria-label="$i18n{passpointDomainsA11yLabel}"
class="settings-box" expanded="{{domainsExpanded_}}">
$i18n{passpointDomainsLabel}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import '../settings_shared.css.js';
import {MojoConnectivityProvider} from 'chrome://resources/ash/common/connectivity/mojo_connectivity_provider.js';
import {PasspointServiceInterface, PasspointSubscription} from 'chrome://resources/ash/common/connectivity/passpoint.mojom-webui.js';
import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js';
import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js';
import {App, AppType, PageHandlerInterface} from 'chrome://resources/cr_components/app_management/app_management.mojom-webui.js';
import {BrowserProxy as AppManagementComponentBrowserProxy} from 'chrome://resources/cr_components/app_management/browser_proxy.js';
import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
import {CrosNetworkConfigInterface, NetworkCertificate} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {CrosNetworkConfigInterface, FilterType, NetworkCertificate, NetworkStateProperties, NO_LIMIT} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js';
import {NetworkType} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js';
import {DomRepeatEvent, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';

import {castExists} from '../assert_extras.js';
import {routes} from '../os_settings_routes.js';
Expand Down Expand Up @@ -62,6 +64,14 @@ export class SettingsPasspointSubpageElement extends PasspointListenerMixin
computed: 'getProviderName_(subscription_, app_)',
},

/** List of networks populated with the subscription. */
networks_: {
type: Array,
value() {
return [];
},
},

/** Tell if the forget dialog should be displayed. */
showForgetDialog_: Boolean,

Expand All @@ -76,6 +86,7 @@ export class SettingsPasspointSubpageElement extends PasspointListenerMixin
private domainsExpanded_: boolean;
private id_: string;
private networkConfig_: CrosNetworkConfigInterface;
private networks_: NetworkStateProperties[];
private passpointService_: PasspointServiceInterface;
private providerName_: string;
private showForgetDialog_: boolean;
Expand Down Expand Up @@ -132,6 +143,7 @@ export class SettingsPasspointSubpageElement extends PasspointListenerMixin
this.subscription_ = response.result;
this.refreshCertificates_();
this.refreshApp_(this.subscription_);
this.refreshNetworks_(this.subscription_);
}

private async refreshCertificates_(): Promise<void> {
Expand All @@ -151,6 +163,19 @@ export class SettingsPasspointSubpageElement extends PasspointListenerMixin
}
}

private async refreshNetworks_(subscription: PasspointSubscription):
Promise<void> {
const filter = {
filter: FilterType.kConfigured,
limit: NO_LIMIT,
networkType: NetworkType.kWiFi,
};
const response = await this.networkConfig_.getNetworkStateList(filter);
this.networks_ = response.result.filter(network => {
return network.typeState!.wifi!.passpointId === subscription.id;
});
}

private getCertificateAuthorityName_(): string {
for (const cert of this.certs_) {
if (cert.pemOrId === this.subscription_!.trustedCa) {
Expand Down Expand Up @@ -180,6 +205,24 @@ export class SettingsPasspointSubpageElement extends PasspointListenerMixin
return this.subscription_!.domains;
}

private getNetworkDisplayName_(networkState: OncMojo.NetworkStateProperties):
string {
return OncMojo.getNetworkStateDisplayName(networkState);
}

private hasNetworks_(): boolean {
return this.networks_.length > 0;
}

private onAssociatedNetworkClicked_(
event: DomRepeatEvent<OncMojo.NetworkStateProperties>): void {
const networkState = event.model.item;
const showDetailEvent = new CustomEvent(
'show-detail', {bubbles: true, composed: true, detail: networkState});
this.dispatchEvent(showDetailEvent);
event.stopPropagation();
}

private getRemovalDialogDescription_(): string {
return this.i18n(
'passpointRemovalDescription', this.subscription_!.friendlyName);
Expand Down
2 changes: 2 additions & 0 deletions chrome/browser/ui/webui/settings/ash/internet_section.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,8 @@ void InternetSection::AddLoadTimeData(content::WebUIDataSource* html_source) {
{"passpointSourceLabel", IDS_SETTINGS_INTERNET_PASSPOINT_SOURCE},
{"passpointTrustedCALabel", IDS_SETTINGS_INTERNET_PASSPOINT_TRUSTED_CA},
{"passpointSystemCALabel", IDS_SETTINGS_INTERNET_PASSPOINT_SYSTEM_CA},
{"passpointAssociatedWifiNetworks",
IDS_SETTINGS_INTERNET_PASSPOINT_ASSOCIATED_WIFI_NETWORKS},
{"passpointDomainsLabel", IDS_SETTINGS_INTERNET_PASSPOINT_DOMAINS},
{"passpointDomainsA11yLabel",
IDS_SETTINGS_INTERNET_PASSPOINT_DOMAINS_A11Y_LABEL},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,18 @@ import {assert} from 'chrome://resources/ash/common/assert.js';
import {MojoConnectivityProvider} from 'chrome://resources/ash/common/connectivity/mojo_connectivity_provider.js';
import {PasspointSubscription} from 'chrome://resources/ash/common/connectivity/passpoint.mojom-webui.js';
import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js';
import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js';
import {AppType} from 'chrome://resources/cr_components/app_management/app_management.mojom-webui.js';
import {CrLinkRowElement} from 'chrome://resources/cr_elements/cr_link_row/cr_link_row.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {CertificateType} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js';
import {NetworkType} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js';
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {assertEquals, assertNull, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {FakeNetworkConfig} from 'chrome://webui-test/chromeos/fake_network_config_mojom.js';
import {FakePasspointService} from 'chrome://webui-test/chromeos/fake_passpoint_service_mojom.js';
import {waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
import {eventToPromise} from 'chrome://webui-test/test_util.js';

import {FakePageHandler} from '../app_management/fake_page_handler.js';
import {setupFakeHandler} from '../app_management/test_util.js';
Expand Down Expand Up @@ -60,11 +64,11 @@ suite('PasspointSubpage', () => {
return flushAsync();
}

function getDomainsListItems() {
const domains = passpointSubpage_.shadowRoot!.querySelector<HTMLDivElement>(
'#passpointDomainsList');
assertTrue(!!domains);
return domains!.querySelectorAll('div.list-item');
function getListItems(id: string) {
const div =
passpointSubpage_.shadowRoot!.querySelector<HTMLDivElement>(`#${id}`);
assertTrue(!!div);
return div!.querySelectorAll('div.list-item');
}

function getExpirationDateItem(): HTMLDivElement|null {
Expand Down Expand Up @@ -143,7 +147,7 @@ suite('PasspointSubpage', () => {
// No app registered, package name should be displayed.
assertEquals(sub.provisioningSource, getSourceText());
// Only one domain in the list.
const list = getDomainsListItems();
const list = getListItems('passpointDomainsList');
assertEquals(1, list.length);
// No expiration time.
const item = getExpirationDateItem();
Expand Down Expand Up @@ -171,7 +175,7 @@ suite('PasspointSubpage', () => {
// No app registered, package name should be displayed.
assertEquals(sub.provisioningSource, getSourceText());
// Only one domain in the list.
const list = getDomainsListItems();
const list = getListItems('passpointDomainsList');
assertEquals(2, list.length);
// Expiration time is displayed.
const item = getExpirationDateItem();
Expand Down Expand Up @@ -214,7 +218,7 @@ suite('PasspointSubpage', () => {
await init(sub);

// Only one domain in the list.
const list = getDomainsListItems();
const list = getListItems('passpointDomainsList');
assertEquals(1, list.length);
// No expiration time.
const item = getExpirationDateItem();
Expand Down Expand Up @@ -267,4 +271,56 @@ suite('PasspointSubpage', () => {
const resp = await passpointServiceApi_!.getPasspointSubscription(subId);
assertEquals(null, resp.result);
});

test('Subscription with no associated networks', async () => {
const subId = 'sub-id';
const sub = {
id: subId,
domains: ['passpoint.example.com'],
friendlyName: 'Passpoint Example Ltd.',
provisioningSource: 'app.passpoint.example.com',
trustedCa: CA_PEM,
expirationEpochMs: 0n,
};
networkConfigApi_.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifi = OncMojo.getDefaultNetworkState(NetworkType.kWiFi, 'wifi');
networkConfigApi_.addNetworksForTest([wifi]);
await init(sub);

const elem = passpointSubpage_.shadowRoot!.querySelector<HTMLDivElement>(
'#passpointNetworksList');
assertNull(elem);
});

test('Subscription with multiple associated networks', async () => {
const subId = 'sub-id';
const sub = {
id: subId,
domains: ['passpoint.example.com'],
friendlyName: 'Passpoint Example Ltd.',
provisioningSource: 'app.passpoint.example.com',
trustedCa: CA_PEM,
expirationEpochMs: 0n,
};
networkConfigApi_.setNetworkTypeEnabledState(NetworkType.kWiFi, true);
const wifi1 = OncMojo.getDefaultNetworkState(NetworkType.kWiFi, 'wifi1');
wifi1.typeState!.wifi!.passpointId = subId;
const wifi2 = OncMojo.getDefaultNetworkState(NetworkType.kWiFi, 'wifi2');
wifi2.typeState!.wifi!.passpointId = subId;
networkConfigApi_.addNetworksForTest([
wifi1,
wifi2,
]);
await init(sub);

const list = getListItems('passpointNetworksList');
assertEquals(2, list.length);
const row = list[0]!.querySelector<CrLinkRowElement>('cr-link-row');
assertTrue(!!row);

const showDetailPromise = eventToPromise('show-detail', window);
row!.click();
const showDetailEvent = await showDetailPromise;
assertEquals('wifi1_guid', showDetailEvent.detail.guid);
});
});
2 changes: 2 additions & 0 deletions chromeos/ash/components/network/network_state.cc
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ bool NetworkState::PropertyChanged(const std::string& key,
return GetIntegerValue(key, value, &priority_);
} else if (key == shill::kWifiHiddenSsid) {
return GetBooleanValue(key, value, &hidden_ssid_);
} else if (key == shill::kPasspointIDProperty) {
return GetStringValue(key, value, &passpoint_id_);
} else if (key == shill::kOutOfCreditsProperty) {
return GetBooleanValue(key, value, &cellular_out_of_credits_);
} else if (key == shill::kIccidProperty) {
Expand Down
2 changes: 2 additions & 0 deletions chromeos/ash/components/network/network_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ class COMPONENT_EXPORT(CHROMEOS_NETWORK) NetworkState : public ManagedState {
blocked_by_policy_ = blocked_by_policy;
}
bool hidden_ssid() const { return hidden_ssid_; }
const std::string& passpoint_id() const { return passpoint_id_; }

// Wifi property accessors
const std::string& eap_method() const { return eap_method_; }
Expand Down Expand Up @@ -366,6 +367,7 @@ class COMPONENT_EXPORT(CHROMEOS_NETWORK) NetworkState : public ManagedState {
int frequency_ = 0;
bool blocked_by_policy_ = false;
bool hidden_ssid_ = false;
std::string passpoint_id_;

// Cellular properties, used for icons, Connect, and Activation.
std::string eid_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,7 @@ mojom::NetworkStatePropertiesPtr NetworkStateToMojo(
wifi->signal_strength = network->signal_strength();
wifi->ssid = network->name();
wifi->hidden_ssid = network->hidden_ssid();
wifi->passpoint_id = network->passpoint_id();
result->type_state =
mojom::NetworkTypeStateProperties::NewWifi(std::move(wifi));
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3630,6 +3630,22 @@ TEST_F(CrosNetworkConfigTest, ESimManagedPropertiesNameComesFromHermes) {
EXPECT_EQ(kTestProfileNickname, properties->name->active_value);
}

// Tests that the Passpoint identifier of a Wi-Fi network is reflected to its
// network state.
TEST_F(CrosNetworkConfigTest, NetworkStateHasPasspointId) {
const char kWifiGuid[] = "wifi_pp_guid";
const char kPasspointId[] = "passpoint_id";
helper()->ConfigureService(base::StringPrintf(
R"({"GUID": "%s", "Type": "wifi", "State": "idle",
"Strength": 90, "AutoConnect": true, "Connectable": true,
"Passpoint.ID": "%s"})",
kWifiGuid, kPasspointId));
mojom::NetworkStatePropertiesPtr network = GetNetworkState(kWifiGuid);
ASSERT_TRUE(network);
EXPECT_EQ(mojom::NetworkType::kWiFi, network->type);
EXPECT_EQ(kPasspointId, network->type_state->get_wifi()->passpoint_id);
}

TEST_F(CrosNetworkConfigTest, GetAlwaysOnVpn) {
mojom::AlwaysOnVpnPropertiesPtr properties;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ struct WiFiStateProperties {
string ssid;
// Whether the AP has a hidden SSID.
bool hidden_ssid;
// Identifier of the set of Passpoint credentials that populated this Wi-Fi
// network.
string passpoint_id;
};

union NetworkTypeStateProperties {
Expand Down

0 comments on commit 272b310

Please sign in to comment.