| // Copyright 2015 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| /** |
| * @fileoverview |
| * 'settings-internet-detail' is the settings subpage containing details |
| * for a network. |
| */ |
| |
| import 'chrome://resources/ash/common/network/cr_policy_network_indicator_mojo.js'; |
| import 'chrome://resources/ash/common/network/network_apnlist.js'; |
| import 'chrome://resources/ash/common/network/network_choose_mobile.js'; |
| import 'chrome://resources/ash/common/network/network_config_toggle.js'; |
| import 'chrome://resources/ash/common/network/network_icon.js'; |
| import 'chrome://resources/ash/common/network/network_ip_config.js'; |
| import 'chrome://resources/ash/common/network/network_nameservers.js'; |
| import 'chrome://resources/ash/common/network/network_property_list_mojo.js'; |
| import 'chrome://resources/ash/common/network/network_siminfo.js'; |
| import 'chrome://resources/cr_components/settings_prefs/prefs.js'; |
| import 'chrome://resources/cr_elements/cr_button/cr_button.js'; |
| import 'chrome://resources/cr_elements/cr_expand_button/cr_expand_button.js'; |
| import 'chrome://resources/cr_elements/cr_shared_vars.css.js'; |
| import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.js'; |
| import 'chrome://resources/cr_elements/icons.html.js'; |
| import 'chrome://resources/cr_elements/policy/cr_policy_indicator.js'; |
| import 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js'; |
| import 'chrome://resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js'; |
| import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; |
| import 'chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js'; |
| import '/shared/settings/controls/controlled_button.js'; |
| import '/shared/settings/controls/settings_toggle_button.js'; |
| import './cellular_roaming_toggle_button.js'; |
| import './internet_shared.css.js'; |
| import './network_proxy_section.js'; |
| import './settings_traffic_counters.js'; |
| import './tether_connection_dialog.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 {isActiveSim, processDeviceState} from 'chrome://resources/ash/common/network/cellular_utils.js'; |
| import {CrPolicyNetworkBehaviorMojo, CrPolicyNetworkBehaviorMojoInterface} from 'chrome://resources/ash/common/network/cr_policy_network_behavior_mojo.js'; |
| import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js'; |
| import {NetworkListenerBehavior, NetworkListenerBehaviorInterface} from 'chrome://resources/ash/common/network/network_listener_behavior.js'; |
| import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js'; |
| import {PrefsMixin, PrefsMixinInterface} from 'chrome://resources/cr_components/settings_prefs/prefs_mixin.js'; |
| import {CrToggleElement} from 'chrome://resources/cr_elements/cr_toggle/cr_toggle.js'; |
| import {I18nMixin, I18nMixinInterface} from 'chrome://resources/cr_elements/i18n_mixin.js'; |
| import {WebUiListenerMixin, WebUiListenerMixinInterface} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js'; |
| import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; |
| import {ActivationStateType, ApnProperties, ConfigProperties, CrosNetworkConfigInterface, GlobalPolicy, HiddenSsidMode, IPConfigProperties, ManagedProperties, MatchType, NetworkStateProperties, ProxySettings, SecurityType, VpnType} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js'; |
| import {ConnectionStateType, DeviceStateType, IPConfigType, NetworkType, OncSource, PolicySource, PortalState} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js'; |
| import {afterNextRender, flush, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; |
| |
| import {assertExists, castExists} from '../assert_extras.js'; |
| import {Constructor} from '../common/types.js'; |
| import {DeepLinkingMixin, DeepLinkingMixinInterface} from '../deep_linking_mixin.js'; |
| import {recordSettingChange} from '../metrics_recorder.js'; |
| import {Setting} from '../mojom-webui/setting.mojom-webui.js'; |
| import {OsSyncBrowserProxy, OsSyncBrowserProxyImpl, OsSyncPrefs} from '../os_people_page/os_sync_browser_proxy.js'; |
| import {OsSettingsSubpageElement} from '../os_settings_page/os_settings_subpage.js'; |
| import {routes} from '../os_settings_routes.js'; |
| import {RouteObserverMixin, RouteObserverMixinInterface} from '../route_observer_mixin.js'; |
| import {Route, Router} from '../router.js'; |
| |
| import {getTemplate} from './internet_detail_subpage.html.js'; |
| import {InternetPageBrowserProxy, InternetPageBrowserProxyImpl} from './internet_page_browser_proxy.js'; |
| import {TetherConnectionDialogElement} from './tether_connection_dialog.js'; |
| |
| const SettingsInternetDetailPageElementBase = |
| mixinBehaviors( |
| [ |
| NetworkListenerBehavior, |
| CrPolicyNetworkBehaviorMojo, |
| ], |
| DeepLinkingMixin(PrefsMixin(RouteObserverMixin( |
| WebUiListenerMixin(I18nMixin(PolymerElement)))))) as |
| Constructor<PolymerElement&I18nMixinInterface&WebUiListenerMixinInterface& |
| RouteObserverMixinInterface&PrefsMixinInterface& |
| DeepLinkingMixinInterface&NetworkListenerBehaviorInterface& |
| CrPolicyNetworkBehaviorMojoInterface>; |
| |
| class SettingsInternetDetailPageElement extends |
| SettingsInternetDetailPageElementBase { |
| static get is() { |
| return 'settings-internet-detail-subpage' as const; |
| } |
| |
| static get template() { |
| return getTemplate(); |
| } |
| |
| static get properties() { |
| return { |
| /** The network GUID to display details for. */ |
| guid: String, |
| |
| /** |
| * Whether network configuration properties sections should be shown. The |
| * advanced section is not controlled by this property. |
| */ |
| showConfigurableSections_: { |
| type: Boolean, |
| value: true, |
| computed: |
| 'computeShowConfigurableSections_(deviceState_, managedProperties_)', |
| }, |
| |
| isWifiSyncEnabled_: Boolean, |
| |
| managedProperties_: { |
| type: Object, |
| observer: 'managedPropertiesChanged_', |
| }, |
| |
| deviceState_: { |
| type: Object, |
| value: null, |
| }, |
| |
| isSecondaryUser_: { |
| type: Boolean, |
| value() { |
| return loadTimeData.getBoolean('isSecondaryUser'); |
| }, |
| readOnly: true, |
| }, |
| |
| primaryUserEmail_: { |
| type: String, |
| value() { |
| return loadTimeData.getBoolean('isSecondaryUser') ? |
| loadTimeData.getString('primaryUserEmail') : |
| ''; |
| }, |
| readOnly: true, |
| }, |
| |
| /** |
| * Whether the network has been lost (e.g., has gone out of range). A |
| * network is considered to be lost when a OnNetworkStateListChanged |
| * is signaled and the new network list does not contain the GUID of the |
| * current network. |
| */ |
| outOfRange_: { |
| type: Boolean, |
| value: false, |
| }, |
| |
| /** |
| * Highest priority connected network or null. |
| */ |
| defaultNetwork: { |
| type: Object, |
| value: null, |
| }, |
| |
| globalPolicy: Object, |
| |
| /** |
| * Whether a managed network is available in the visible network list. |
| */ |
| managedNetworkAvailable: { |
| type: Boolean, |
| value: false, |
| }, |
| |
| /** |
| * The network AutoConnect state as a fake preference object. |
| */ |
| autoConnectPref_: { |
| type: Object, |
| observer: 'autoConnectPrefChanged_', |
| value() { |
| return { |
| key: 'fakeAutoConnectPref', |
| type: chrome.settingsPrivate.PrefType.BOOLEAN, |
| value: false, |
| }; |
| }, |
| }, |
| |
| /** |
| * The network hidden state as a fake preference object. |
| */ |
| hiddenPref_: { |
| type: Object, |
| observer: 'hiddenPrefChanged_', |
| value() { |
| return { |
| key: 'fakeHiddenPref', |
| type: chrome.settingsPrivate.PrefType.BOOLEAN, |
| value: false, |
| }; |
| }, |
| }, |
| |
| /** |
| * The always-on VPN state as a fake preference object. |
| */ |
| alwaysOnVpn_: { |
| type: Object, |
| observer: 'alwaysOnVpnChanged_', |
| value() { |
| return { |
| key: 'fakeAlwaysOnPref', |
| type: chrome.settingsPrivate.PrefType.BOOLEAN, |
| value: false, |
| }; |
| }, |
| }, |
| |
| /** |
| * This gets initialized to managedProperties_.metered.activeValue. |
| * When this is changed from the UI, a change event will update the |
| * property and setMojoNetworkProperties will be called. |
| */ |
| meteredOverride_: { |
| type: Boolean, |
| value: false, |
| }, |
| |
| /** |
| * The network preferred state. |
| */ |
| preferNetwork_: { |
| type: Boolean, |
| value: false, |
| observer: 'preferNetworkChanged_', |
| }, |
| |
| /** |
| * The network IP Address. |
| */ |
| ipAddress_: { |
| type: String, |
| value: '', |
| }, |
| |
| /** |
| * Whether to show technology badge on mobile network icons. |
| */ |
| showTechnologyBadge_: { |
| type: Boolean, |
| value() { |
| return loadTimeData.valueExists('showTechnologyBadge') && |
| loadTimeData.getBoolean('showTechnologyBadge'); |
| }, |
| }, |
| |
| showMeteredToggle_: { |
| type: Boolean, |
| value() { |
| return loadTimeData.valueExists('showMeteredToggle') && |
| loadTimeData.getBoolean('showMeteredToggle'); |
| }, |
| }, |
| |
| /** |
| * Whether to show the Hidden toggle on configured wifi networks (flag). |
| */ |
| showHiddenToggle_: { |
| type: Boolean, |
| value() { |
| return loadTimeData.valueExists('showHiddenToggle') && |
| loadTimeData.getBoolean('showHiddenToggle'); |
| }, |
| }, |
| |
| isTrafficCountersEnabled_: { |
| type: Boolean, |
| value() { |
| return loadTimeData.valueExists('trafficCountersEnabled') && |
| loadTimeData.getBoolean('trafficCountersEnabled'); |
| }, |
| }, |
| |
| /** |
| * When true, all inputs that allow state to be changed (e.g., toggles, |
| * inputs) are disabled. |
| */ |
| disabled_: { |
| type: Boolean, |
| value: false, |
| computed: 'computeDisabled_(deviceState_.*)', |
| }, |
| |
| enableHiddenNetworkMigration_: { |
| type: Boolean, |
| value() { |
| return loadTimeData.valueExists('enableHiddenNetworkMigration') && |
| loadTimeData.getBoolean('enableHiddenNetworkMigration'); |
| }, |
| }, |
| |
| isApnRevampEnabled_: { |
| type: Boolean, |
| value() { |
| return loadTimeData.valueExists('isApnRevampEnabled') && |
| loadTimeData.getBoolean('isApnRevampEnabled'); |
| }, |
| }, |
| |
| isPasspointEnabled_: { |
| type: Boolean, |
| value() { |
| return loadTimeData.valueExists('isPasspointEnabled') && |
| loadTimeData.getBoolean('isPasspointEnabled'); |
| }, |
| }, |
| |
| isPasspointSettingsEnabled_: { |
| type: Boolean, |
| readOnly: true, |
| value() { |
| return loadTimeData.valueExists('isPasspointSettingsEnabled') && |
| loadTimeData.getBoolean('isPasspointSettingsEnabled'); |
| }, |
| }, |
| |
| passpointSubscription_: { |
| type: Object, |
| notify: true, |
| }, |
| |
| advancedExpanded_: Boolean, |
| |
| networkExpanded_: Boolean, |
| |
| proxyExpanded_: Boolean, |
| |
| dataUsageExpanded_: Boolean, |
| |
| /** |
| * Used by DeepLinkingMixin to focus this page's deep links. |
| */ |
| supportedSettingIds: { |
| type: Object, |
| value: () => new Set<Setting>([ |
| Setting.kConfigureEthernet, |
| Setting.kEthernetAutoConfigureIp, |
| Setting.kEthernetDns, |
| Setting.kEthernetProxy, |
| Setting.kDisconnectWifiNetwork, |
| Setting.kPreferWifiNetwork, |
| Setting.kForgetWifiNetwork, |
| Setting.kWifiAutoConfigureIp, |
| Setting.kWifiDns, |
| Setting.kWifiHidden, |
| Setting.kWifiProxy, |
| Setting.kWifiAutoConnectToNetwork, |
| Setting.kCellularSimLock, |
| Setting.kCellularRoaming, |
| Setting.kCellularApn, |
| Setting.kDisconnectCellularNetwork, |
| Setting.kCellularAutoConfigureIp, |
| Setting.kCellularDns, |
| Setting.kCellularProxy, |
| Setting.kCellularAutoConnectToNetwork, |
| Setting.kDisconnectTetherNetwork, |
| Setting.kWifiMetered, |
| Setting.kCellularMetered, |
| ]), |
| }, |
| }; |
| } |
| |
| static get observers() { |
| return [ |
| 'updateAlwaysOnVpnPrefValue_(prefs.arc.vpn.always_on.*)', |
| 'updateAlwaysOnVpnPrefEnforcement_(managedProperties_,' + |
| 'prefs.vpn_config_allowed.*)', |
| 'updateAutoConnectPref_(globalPolicy)', |
| 'autoConnectPrefChanged_(autoConnectPref_.*)', |
| 'alwaysOnVpnChanged_(alwaysOnVpn_.*)', |
| 'hiddenPrefChanged_(hiddenPref_.*)', |
| ]; |
| } |
| |
| /* eslint-disable-next-line @typescript-eslint/naming-convention */ |
| CR_EXPAND_BUTTON_TAG: string; |
| defaultNetwork: OncMojo.NetworkStateProperties|null; |
| globalPolicy?: GlobalPolicy; |
| guid: string; |
| managedNetworkAvailable: boolean; |
| private advancedExpanded_: boolean; |
| private alwaysOnVpn_: chrome.settingsPrivate.PrefObject<boolean>; |
| private applyingChanges_: boolean; |
| private autoConnectPref_: chrome.settingsPrivate.PrefObject<boolean>; |
| private browserProxy_: InternetPageBrowserProxy; |
| private dataUsageExpanded_: boolean; |
| private deviceState_: OncMojo.DeviceStateProperties|null; |
| private didSetFocus_: boolean; |
| private disabled_: boolean; |
| private enableHiddenNetworkMigration_: boolean; |
| private hiddenPref_: chrome.settingsPrivate.PrefObject<boolean>; |
| private ipAddress_: string; |
| private isApnRevampEnabled_: boolean; |
| private isPasspointEnabled_: boolean; |
| private isPasspointSettingsEnabled_: boolean; |
| private isSecondaryUser_: boolean; |
| private isTrafficCountersEnabled_: boolean; |
| private isWifiSyncEnabled_: boolean; |
| private managedProperties_: ManagedProperties|undefined; |
| private meteredOverride_: boolean; |
| private networkConfig_: CrosNetworkConfigInterface; |
| private networkExpanded_: boolean; |
| private osSyncBrowserProxy_: OsSyncBrowserProxy; |
| private outOfRange_: boolean; |
| private passpointService_: PasspointServiceInterface; |
| private passpointSubscription_: PasspointSubscription|null; |
| private pendingSimLockDeepLink_: boolean; |
| private preferNetwork_: boolean; |
| private primaryUserEmail_: string; |
| private propertiesReceived_: boolean; |
| private proxyExpanded_: boolean; |
| private shouldShowConfigureWhenNetworkLoaded_: boolean; |
| private showConfigurableSections_: boolean; |
| private showHiddenToggle_: boolean; |
| private showMeteredToggle_: boolean; |
| private showTechnologyBadge_: string; |
| |
| constructor() { |
| super(); |
| |
| this.CR_EXPAND_BUTTON_TAG = 'CR-EXPAND-BUTTON'; |
| |
| this.didSetFocus_ = false; |
| |
| /** |
| * Set to true to once the initial properties have been received. This |
| * prevents setProperties from being called when setting default properties. |
| */ |
| this.propertiesReceived_ = false; |
| |
| /** |
| * Set in currentRouteChanged() if the showConfigure URL query |
| * parameter is set to true. The dialog cannot be shown until the |
| * network properties have been fetched in managedPropertiesChanged_(). |
| */ |
| this.shouldShowConfigureWhenNetworkLoaded_ = false; |
| |
| /** |
| * Prevents re-saving incoming changes. |
| */ |
| this.applyingChanges_ = false; |
| |
| /** |
| * Flag, if true, indicating that the next deviceState_ update |
| * should call deepLinkToSimLockElement_(). |
| */ |
| this.pendingSimLockDeepLink_ = false; |
| |
| this.browserProxy_ = InternetPageBrowserProxyImpl.getInstance(); |
| |
| this.networkConfig_ = |
| MojoInterfaceProviderImpl.getInstance().getMojoServiceRemote(); |
| |
| if (this.isPasspointSettingsEnabled_) { |
| this.passpointService_ = |
| MojoConnectivityProvider.getInstance().getPasspointService(); |
| } |
| |
| this.osSyncBrowserProxy_ = OsSyncBrowserProxyImpl.getInstance(); |
| } |
| |
| override connectedCallback(): void { |
| super.connectedCallback(); |
| |
| this.addWebUiListener( |
| 'os-sync-prefs-changed', this.handleOsSyncPrefsChanged_.bind(this)); |
| this.osSyncBrowserProxy_.sendOsSyncPrefsChanged(); |
| } |
| |
| private afterRenderShowDeepLink_( |
| settingId: Setting, elementCallback: () => HTMLElement | null): void { |
| // Wait for element to load. |
| afterNextRender(this, () => { |
| const deepLinkElement = elementCallback(); |
| if (!deepLinkElement || deepLinkElement.hidden) { |
| console.warn(`Element with deep link id ${settingId} not focusable.`); |
| return; |
| } |
| this.showDeepLinkElement(deepLinkElement); |
| }); |
| } |
| |
| /** |
| * Overridden from DeepLinkingMixin. |
| */ |
| override beforeDeepLinkAttempt(settingId: Setting): boolean { |
| // Manually show the deep links for settings in shared elements. |
| if (settingId === Setting.kCellularRoaming) { |
| this.afterRenderShowDeepLink_( |
| settingId, |
| () => |
| this.shadowRoot!.querySelector('cellular-roaming-toggle-button')! |
| .getCellularRoamingToggle()); |
| // Stop deep link attempt since we completed it manually. |
| return false; |
| } |
| |
| if (settingId === Setting.kCellularApn) { |
| this.networkExpanded_ = true; |
| this.afterRenderShowDeepLink_( |
| settingId, |
| () => this.shadowRoot!.querySelector( |
| 'network-apnlist')!.getApnSelect()); |
| return false; |
| } |
| |
| if (settingId === Setting.kEthernetAutoConfigureIp || |
| settingId === Setting.kWifiAutoConfigureIp || |
| settingId === Setting.kCellularAutoConfigureIp) { |
| this.networkExpanded_ = true; |
| this.afterRenderShowDeepLink_( |
| settingId, |
| () => this.shadowRoot!.querySelector('network-ip-config')! |
| .getAutoConfigIpToggle()); |
| return false; |
| } |
| |
| if (settingId === Setting.kEthernetDns || settingId === Setting.kWifiDns || |
| settingId === Setting.kCellularDns) { |
| this.networkExpanded_ = true; |
| this.afterRenderShowDeepLink_( |
| settingId, |
| () => this.shadowRoot!.querySelector('network-nameservers')! |
| .getNameserverRadioButtons()); |
| return false; |
| } |
| |
| if (settingId === Setting.kEthernetProxy || |
| settingId === Setting.kWifiProxy || |
| settingId === Setting.kCellularProxy) { |
| this.proxyExpanded_ = true; |
| this.afterRenderShowDeepLink_( |
| settingId, |
| () => this.shadowRoot!.querySelector('network-proxy-section')! |
| .getAllowSharedToggle()); |
| return false; |
| } |
| |
| if (settingId === Setting.kWifiMetered || |
| settingId === Setting.kCellularMetered) { |
| this.advancedExpanded_ = true; |
| // Continue with automatically showing these deep links. |
| return true; |
| } |
| |
| if (settingId === Setting.kForgetWifiNetwork) { |
| this.afterRenderShowDeepLink_(settingId, () => { |
| const forgetButton = this.shadowRoot!.getElementById('forgetButton'); |
| if (forgetButton && !forgetButton.hidden) { |
| return forgetButton; |
| } |
| // If forget button is hidden, show disconnect button instead. |
| return this.shadowRoot!.getElementById('connectDisconnect'); |
| }); |
| return false; |
| } |
| |
| if (settingId === Setting.kCellularSimLock) { |
| this.advancedExpanded_ = true; |
| |
| // If the page just loaded, deviceState_ will not be fully initialized |
| // yet, so we won't know which SIM info element to focus. Set |
| // pendingSimLockDeepLink_ to indicate that a SIM info element should be |
| // focused next deviceState_ update. |
| this.pendingSimLockDeepLink_ = true; |
| return false; |
| } |
| |
| // Otherwise, should continue with deep link attempt. |
| return true; |
| } |
| |
| /** |
| * RouteObserverMixin override |
| */ |
| override currentRouteChanged(route: Route, oldRoute?: Route): void { |
| if (route !== routes.NETWORK_DETAIL) { |
| return; |
| } |
| |
| const queryParams = Router.getInstance().getQueryParameters(); |
| const guid = queryParams.get('guid') || ''; |
| if (!guid) { |
| console.warn('No guid specified for page:' + route); |
| this.close(); |
| } |
| |
| this.shouldShowConfigureWhenNetworkLoaded_ = |
| queryParams.get('showConfigure') === 'true'; |
| const type = queryParams.get('type') || 'WiFi'; |
| const name = queryParams.get('name') || type; |
| this.init(guid, type, name); |
| |
| // If we are getting back from APN subpage set focus to the APN subpage |
| // row. |
| if (oldRoute === routes.APN && |
| Router.getInstance().lastRouteChangeWasPopstate()) { |
| this.didSetFocus_ = true; |
| afterNextRender(this, () => { |
| const element = this.shadowRoot!.getElementById('apnSubpageButton'); |
| if (element) { |
| element.focus(); |
| } |
| }); |
| } |
| this.attemptDeepLink(); |
| } |
| |
| /** |
| * Handler for when os sync preferences are updated. |
| */ |
| private handleOsSyncPrefsChanged_(osSyncPrefs: OsSyncPrefs): void { |
| this.isWifiSyncEnabled_ = |
| !!osSyncPrefs && osSyncPrefs.osWifiConfigurationsSynced; |
| } |
| |
| init(guid: string, type: string, name: string): void { |
| this.guid = guid; |
| // Set default properties until they are loaded. |
| this.propertiesReceived_ = false; |
| this.deviceState_ = null; |
| this.managedProperties_ = OncMojo.getDefaultManagedProperties( |
| OncMojo.getNetworkTypeFromString(type), this.guid, name); |
| this.didSetFocus_ = false; |
| this.getNetworkDetails_(); |
| } |
| |
| close(): void { |
| // If the page is already closed, return early to avoid navigating backward |
| // erroneously. |
| if (!this.guid) { |
| return; |
| } |
| |
| this.guid = ''; |
| |
| // Delay navigating to allow other subpages to load first. |
| requestAnimationFrame(() => { |
| // Clear network properties before navigating away to ensure that a future |
| // navigation back to the details page does not show a flicker of |
| // incorrect text. See https://crbug.com/905986. |
| this.managedProperties_ = undefined; |
| this.propertiesReceived_ = false; |
| |
| if (Router.getInstance().currentRoute === routes.NETWORK_DETAIL) { |
| Router.getInstance().navigateToPreviousRoute(); |
| } |
| }); |
| } |
| |
| /** CrosNetworkConfigObserver impl */ |
| override onActiveNetworksChanged(networks: OncMojo.NetworkStateProperties[]): |
| void { |
| if (!this.guid || !this.managedProperties_) { |
| return; |
| } |
| // If the network was or is active, request an update. |
| if (this.managedProperties_.connectionState !== |
| ConnectionStateType.kNotConnected || |
| networks.find(network => network.guid === this.guid)) { |
| this.getNetworkDetails_(); |
| } |
| } |
| |
| /** CrosNetworkConfigObserver impl */ |
| override onNetworkStateChanged(network: NetworkStateProperties): void { |
| if (!this.guid || !this.managedProperties_) { |
| return; |
| } |
| if (network.guid === this.guid) { |
| this.getNetworkDetails_(); |
| } |
| } |
| |
| /** CrosNetworkConfigObserver impl */ |
| override onNetworkStateListChanged(): void { |
| if (!this.guid || !this.managedProperties_) { |
| return; |
| } |
| this.checkNetworkExists_(); |
| } |
| |
| /** CrosNetworkConfigObserver impl */ |
| override onDeviceStateListChanged(): void { |
| if (!this.guid || !this.managedProperties_) { |
| return; |
| } |
| this.getDeviceState_(); |
| } |
| |
| private managedPropertiesChanged_(): void { |
| if (!this.managedProperties_) { |
| return; |
| } |
| this.updateAutoConnectPref_(); |
| this.updateHiddenPref_(); |
| |
| const metered = this.managedProperties_.metered; |
| if (metered && metered.activeValue !== this.meteredOverride_) { |
| this.meteredOverride_ = metered.activeValue; |
| } |
| |
| const priority = this.managedProperties_.priority; |
| if (priority) { |
| const preferNetwork = priority.activeValue > 0; |
| if (preferNetwork !== this.preferNetwork_) { |
| this.preferNetwork_ = preferNetwork; |
| } |
| } |
| |
| // Set the IPAddress property to the IPv4 Address. |
| const ipv4 = |
| OncMojo.getIPConfigForType(this.managedProperties_, IPConfigType.kIPv4); |
| this.ipAddress_ = (ipv4 && ipv4.ipAddress) || ''; |
| |
| // Update the detail page title. |
| const networkName = OncMojo.getNetworkName(this.managedProperties_); |
| (this.parentNode as OsSettingsSubpageElement).pageTitle = networkName; |
| flush(); |
| |
| if (!this.didSetFocus_ && |
| !Router.getInstance().getQueryParameters().has('search') && |
| !this.getDeepLinkSettingId()) { |
| // Unless the page was navigated to via search or has a deep linked |
| // setting, focus a button once the initial state is set. |
| this.didSetFocus_ = true; |
| const button = this.shadowRoot!.querySelector<HTMLButtonElement>( |
| '#titleDiv .action-button:not([hidden])'); |
| if (button) { |
| afterNextRender(this, () => button.focus()); |
| } |
| } |
| |
| if (this.shouldShowConfigureWhenNetworkLoaded_ && |
| this.managedProperties_.type === NetworkType.kTether) { |
| // Set |this.shouldShowConfigureWhenNetworkLoaded_| back to false to |
| // ensure that the Tether dialog is only shown once. |
| this.shouldShowConfigureWhenNetworkLoaded_ = false; |
| // Async call to ensure dialog is stamped. |
| setTimeout(() => this.showTetherDialog_()); |
| } |
| } |
| |
| private async getDeviceState_(): Promise<void> { |
| if (!this.managedProperties_) { |
| return; |
| } |
| const type = this.managedProperties_.type; |
| const response = await this.networkConfig_.getDeviceStateList(); |
| |
| // If there is no GUID, the page was closed between requesting the device |
| // state and receiving it. If this occurs, there is no need to process the |
| // response. Note that if this subpage is reopened later, we'll request |
| // this data again. |
| if (!this.guid) { |
| return; |
| } |
| |
| const {deviceState, shouldGetNetworkDetails} = |
| processDeviceState(type, response.result, this.deviceState_); |
| this.deviceState_ = deviceState; |
| if (shouldGetNetworkDetails) { |
| this.getNetworkDetails_(); |
| } |
| if (this.pendingSimLockDeepLink_) { |
| this.pendingSimLockDeepLink_ = false; |
| this.deepLinkToSimLockElement_(); |
| } |
| } |
| |
| private deepLinkToSimLockElement_(): void { |
| const settingId = Setting.kCellularSimLock; |
| const simLockStatus = this.deviceState_!.simLockStatus; |
| |
| // In this rare case, element not focusable until after a second wait. |
| // This is slightly preferable to requestAnimationFrame used within |
| // network-siminfo to focus elements since it can be reproduced in |
| // testing. |
| afterNextRender(this, () => { |
| if (simLockStatus && !!simLockStatus.lockType) { |
| this.afterRenderShowDeepLink_( |
| settingId, |
| () => this.shadowRoot!.querySelector( |
| 'network-siminfo')!.getUnlockButton()); |
| return; |
| } |
| this.afterRenderShowDeepLink_( |
| settingId, |
| () => this.shadowRoot!.querySelector( |
| 'network-siminfo')!.getSimLockToggle()); |
| }); |
| } |
| |
| private autoConnectPrefChanged_(): void { |
| if (!this.propertiesReceived_) { |
| return; |
| } |
| const config = this.getDefaultConfigProperties_(); |
| config.autoConnect = {value: !!this.autoConnectPref_.value}; |
| this.setMojoNetworkProperties_(config); |
| } |
| |
| private hiddenPrefChanged_(): void { |
| if (!this.propertiesReceived_) { |
| return; |
| } |
| recordSettingChange( |
| Setting.kWifiHidden, {boolValue: !!this.hiddenPref_.value}); |
| const config = this.getDefaultConfigProperties_(); |
| config.typeConfig.wifi!.hiddenSsid = this.hiddenPref_.value ? |
| HiddenSsidMode.kEnabled : |
| HiddenSsidMode.kDisabled; |
| this.setMojoNetworkProperties_(config); |
| } |
| |
| |
| private getPolicyEnforcement_(policySource: PolicySource): |
| chrome.settingsPrivate.Enforcement|undefined { |
| switch (policySource) { |
| case PolicySource.kUserPolicyEnforced: |
| case PolicySource.kDevicePolicyEnforced: |
| return chrome.settingsPrivate.Enforcement.ENFORCED; |
| |
| case PolicySource.kUserPolicyRecommended: |
| case PolicySource.kDevicePolicyRecommended: |
| return chrome.settingsPrivate.Enforcement.RECOMMENDED; |
| |
| default: |
| return undefined; |
| } |
| } |
| |
| private getPolicyController_(policySource: PolicySource): |
| chrome.settingsPrivate.ControlledBy|undefined { |
| switch (policySource) { |
| case PolicySource.kDevicePolicyEnforced: |
| case PolicySource.kDevicePolicyRecommended: |
| return chrome.settingsPrivate.ControlledBy.DEVICE_POLICY; |
| |
| case PolicySource.kUserPolicyEnforced: |
| case PolicySource.kUserPolicyRecommended: |
| return chrome.settingsPrivate.ControlledBy.USER_POLICY; |
| |
| default: |
| return undefined; |
| } |
| } |
| |
| /** |
| * Updates auto-connect pref value. |
| */ |
| private updateAutoConnectPref_(): void { |
| if (!this.managedProperties_) { |
| return; |
| } |
| const autoConnect = OncMojo.getManagedAutoConnect(this.managedProperties_); |
| if (!autoConnect) { |
| return; |
| } |
| |
| let enforcement: chrome.settingsPrivate.Enforcement|undefined; |
| let controlledBy: chrome.settingsPrivate.ControlledBy|undefined; |
| |
| if (this.globalPolicy && |
| this.globalPolicy.allowOnlyPolicyNetworksToAutoconnect) { |
| enforcement = chrome.settingsPrivate.Enforcement.ENFORCED; |
| controlledBy = chrome.settingsPrivate.ControlledBy.DEVICE_POLICY; |
| } else { |
| enforcement = this.getPolicyEnforcement_(autoConnect.policySource); |
| controlledBy = this.getPolicyController_(autoConnect.policySource); |
| } |
| |
| if (this.autoConnectPref_.value === autoConnect.activeValue && |
| enforcement === this.autoConnectPref_.enforcement && |
| controlledBy === this.autoConnectPref_.controlledBy) { |
| return; |
| } |
| |
| const newPrefValue: chrome.settingsPrivate.PrefObject<boolean> = { |
| key: 'fakeAutoConnectPref', |
| value: autoConnect.activeValue, |
| type: chrome.settingsPrivate.PrefType.BOOLEAN, |
| }; |
| if (enforcement) { |
| newPrefValue.enforcement = enforcement; |
| newPrefValue.controlledBy = controlledBy; |
| } |
| |
| this.autoConnectPref_ = newPrefValue; |
| } |
| |
| private updateHiddenPref_(): void { |
| if (!this.managedProperties_) { |
| return; |
| } |
| |
| if (this.managedProperties_.type !== NetworkType.kWiFi) { |
| return; |
| } |
| |
| const hidden = this.managedProperties_.typeProperties.wifi!.hiddenSsid; |
| if (!hidden) { |
| return; |
| } |
| |
| const enforcement = this.getPolicyEnforcement_(hidden.policySource); |
| const controlledBy = this.getPolicyController_(hidden.policySource); |
| if (this.hiddenPref_.value === hidden.activeValue && |
| enforcement === this.hiddenPref_.enforcement && |
| controlledBy === this.hiddenPref_.controlledBy) { |
| return; |
| } |
| |
| const newPrefValue: chrome.settingsPrivate.PrefObject<boolean> = { |
| key: 'fakeHiddenPref', |
| value: hidden.activeValue, |
| type: chrome.settingsPrivate.PrefType.BOOLEAN, |
| }; |
| if (enforcement) { |
| newPrefValue.enforcement = enforcement; |
| newPrefValue.controlledBy = controlledBy; |
| } |
| |
| this.hiddenPref_ = newPrefValue; |
| } |
| |
| private meteredChanged_(e: CustomEvent<{value: boolean}>): void { |
| if (!this.propertiesReceived_) { |
| return; |
| } |
| const config = this.getDefaultConfigProperties_(); |
| config.metered = {value: e.detail.value}; |
| this.setMojoNetworkProperties_(config); |
| } |
| |
| private preferNetworkChanged_(): void { |
| if (!this.propertiesReceived_) { |
| return; |
| } |
| const config = this.getDefaultConfigProperties_(); |
| config.priority = {value: this.preferNetwork_ ? 1 : 0}; |
| this.setMojoNetworkProperties_(config); |
| } |
| |
| private async checkNetworkExists_(): Promise<void> { |
| const response = await this.networkConfig_.getNetworkState(this.guid); |
| if (response.result) { |
| // Don't update the state, a change event will trigger the update. |
| return; |
| } |
| this.outOfRange_ = true; |
| if (this.managedProperties_) { |
| // Set the connection state since we won't receive an update for a non |
| // existent network. |
| this.managedProperties_.connectionState = |
| ConnectionStateType.kNotConnected; |
| } |
| } |
| |
| private async getNetworkDetails_(): Promise<void> { |
| assertExists(this.guid); |
| |
| if (this.isSecondaryUser_) { |
| const response = await this.networkConfig_.getNetworkState(this.guid); |
| this.getStateCallback_(response.result); |
| } else { |
| const response = |
| await this.networkConfig_.getManagedProperties(this.guid); |
| this.getPropertiesCallback_(response.result); |
| if (this.isPasspointSettingsEnabled_ && |
| this.isPasspointWifi_(this.managedProperties_)) { |
| const response = await this.passpointService_.getPasspointSubscription( |
| this.managedProperties_!.typeProperties.wifi!.passpointId!); |
| this.passpointSubscription_ = response.result; |
| } |
| } |
| } |
| |
| private getPropertiesCallback_(properties: ManagedProperties|null): void { |
| // Details page was closed while request was in progress, ignore the result. |
| if (!this.guid) { |
| return; |
| } |
| |
| if (!properties) { |
| // Close the page if the network was removed and no longer exists. |
| this.close(); |
| return; |
| } |
| |
| this.updateManagedProperties_(properties); |
| |
| // Detail page should not be shown when Arc VPN is not connected. |
| if (this.isArcVpn_(this.managedProperties_) && |
| !this.isConnectedState_(this.managedProperties_)) { |
| this.guid = ''; |
| this.close(); |
| } |
| this.propertiesReceived_ = true; |
| this.outOfRange_ = false; |
| if (!this.deviceState_) { |
| this.getDeviceState_(); |
| } |
| } |
| |
| private updateManagedProperties_(properties: ManagedProperties): void { |
| this.applyingChanges_ = true; |
| if (this.managedProperties_ && |
| this.managedProperties_.type === NetworkType.kCellular && |
| this.deviceState_ && this.deviceState_.scanning) { |
| // Cellular properties may be invalid while scanning, so keep the existing |
| // properties instead. |
| properties.typeProperties.cellular = |
| this.managedProperties_.typeProperties.cellular; |
| } |
| this.managedProperties_ = properties; |
| afterNextRender(this, () => { |
| this.applyingChanges_ = false; |
| }); |
| } |
| |
| private getStateCallback_(networkState: OncMojo.NetworkStateProperties| |
| null): void { |
| if (!networkState) { |
| // Edge case, may occur when disabling. Close this. |
| this.close(); |
| return; |
| } |
| |
| const managedProperties = OncMojo.getDefaultManagedProperties( |
| networkState.type, networkState.guid, networkState.name); |
| managedProperties.connectable = networkState.connectable; |
| managedProperties.connectionState = networkState.connectionState; |
| switch (networkState.type) { |
| case NetworkType.kCellular: |
| managedProperties.typeProperties.cellular!.signalStrength = |
| networkState.typeState.cellular!.signalStrength; |
| managedProperties.typeProperties.cellular!.simLocked = |
| networkState.typeState.cellular!.simLocked; |
| break; |
| case NetworkType.kTether: |
| managedProperties.typeProperties.tether!.signalStrength = |
| networkState.typeState.tether!.signalStrength; |
| break; |
| case NetworkType.kWiFi: |
| managedProperties.typeProperties.wifi!.signalStrength = |
| networkState.typeState.wifi!.signalStrength; |
| break; |
| } |
| this.updateManagedProperties_(managedProperties); |
| |
| this.propertiesReceived_ = true; |
| this.outOfRange_ = false; |
| } |
| |
| private getNetworkState_(properties: ManagedProperties): |
| OncMojo.NetworkStateProperties|undefined { |
| if (!properties) { |
| return undefined; |
| } |
| return OncMojo.managedPropertiesToNetworkState(properties); |
| } |
| |
| private getDefaultConfigProperties_(): ConfigProperties { |
| return OncMojo.getDefaultConfigProperties(this.managedProperties_!.type); |
| } |
| |
| |
| private async setMojoNetworkProperties_(config: ConfigProperties): |
| Promise<void> { |
| if (!this.propertiesReceived_ || !this.guid || this.applyingChanges_) { |
| return; |
| } |
| recordSettingChange(); |
| const response = await this.networkConfig_.setProperties(this.guid, config); |
| if (!response.success) { |
| console.warn('Unable to set properties: ' + JSON.stringify(config)); |
| // An error typically indicates invalid input; request the properties |
| // to update any invalid fields. |
| this.getNetworkDetails_(); |
| } |
| } |
| |
| private getStateText_( |
| managedProperties: ManagedProperties, propertiesReceived: boolean, |
| outOfRange: boolean, |
| deviceState: OncMojo.DeviceStateProperties|null): string { |
| if (!managedProperties || !propertiesReceived) { |
| return ''; |
| } |
| |
| if (this.isOutOfRangeOrNotEnabled_(outOfRange, deviceState)) { |
| return managedProperties.type === NetworkType.kTether ? |
| this.i18n('tetherPhoneOutOfRange') : |
| this.i18n('networkOutOfRange'); |
| } |
| |
| if (OncMojo.connectionStateIsConnected(managedProperties.connectionState)) { |
| if (this.isPortalState_(managedProperties.portalState)) { |
| return this.i18n('networkListItemSignIn'); |
| } |
| if (managedProperties.portalState === PortalState.kPortalSuspected) { |
| return this.i18n('networkListItemConnectedLimited'); |
| } |
| if (managedProperties.portalState === PortalState.kNoInternet) { |
| return this.i18n('networkListItemConnectedNoConnectivity'); |
| } |
| } |
| |
| return this.i18n( |
| OncMojo.getConnectionStateString(managedProperties.connectionState)); |
| } |
| |
| private getAutoConnectToggleLabel_(managedProperties: ManagedProperties): |
| string { |
| return this.isCellular_(managedProperties) ? |
| this.i18n('networkAutoConnectCellular') : |
| this.i18n('networkAutoConnect'); |
| } |
| |
| private isConnectedState_(managedProperties: ManagedProperties| |
| undefined): boolean { |
| return !!managedProperties && |
| OncMojo.connectionStateIsConnected(managedProperties.connectionState); |
| } |
| |
| private isRestrictedConnectivity_(managedProperties: ManagedProperties| |
| undefined): boolean { |
| return !!managedProperties && |
| OncMojo.isRestrictedConnectivity(managedProperties.portalState); |
| } |
| |
| private showConnectedState_(managedProperties: ManagedProperties| |
| undefined): boolean { |
| return this.isConnectedState_(managedProperties) && |
| !this.isRestrictedConnectivity_(managedProperties); |
| } |
| |
| private showRestrictedConnectivity_(managedProperties: ManagedProperties| |
| undefined): boolean { |
| if (!managedProperties) { |
| return false; |
| } |
| |
| // State must be connected and restricted. |
| return this.isConnectedState_(managedProperties) && |
| this.isRestrictedConnectivity_(managedProperties); |
| } |
| |
| private isRemembered_(managedProperties: ManagedProperties| |
| undefined): boolean { |
| return !!managedProperties && managedProperties.source !== OncSource.kNone; |
| } |
| |
| private isRememberedOrConnected_(managedProperties: ManagedProperties| |
| undefined): boolean { |
| return this.isRemembered_(managedProperties) || |
| this.isConnectedState_(managedProperties); |
| } |
| |
| private isCellular_(managedProperties: ManagedProperties|undefined): boolean { |
| return !!managedProperties && |
| managedProperties.type === NetworkType.kCellular; |
| } |
| |
| private isTether_(managedProperties: ManagedProperties|undefined): boolean { |
| return !!managedProperties && |
| managedProperties.type === NetworkType.kTether; |
| } |
| |
| private isWireGuard_(managedProperties: ManagedProperties| |
| undefined): boolean { |
| if (!managedProperties) { |
| return false; |
| } |
| if (managedProperties.type !== NetworkType.kVPN) { |
| return false; |
| } |
| if (!managedProperties.typeProperties.vpn) { |
| return false; |
| } |
| return managedProperties.typeProperties.vpn.type === VpnType.kWireGuard; |
| } |
| |
| private isBlockedByPolicy_( |
| managedProperties: ManagedProperties|undefined, |
| globalPolicy: GlobalPolicy|undefined, |
| managedNetworkAvailable: boolean): boolean { |
| if (!managedProperties || !globalPolicy || |
| this.isPolicySource(managedProperties.source)) { |
| return false; |
| } |
| |
| if (managedProperties.type === NetworkType.kCellular && |
| !!globalPolicy.allowOnlyPolicyCellularNetworks) { |
| return true; |
| } |
| |
| if (managedProperties.type !== NetworkType.kWiFi) { |
| return false; |
| } |
| const hexSsid = |
| OncMojo.getActiveString(managedProperties.typeProperties.wifi!.hexSsid); |
| return !!globalPolicy.allowOnlyPolicyWifiNetworksToConnect || |
| (!!globalPolicy.allowOnlyPolicyWifiNetworksToConnectIfAvailable && |
| !!managedNetworkAvailable) || |
| (!!hexSsid && !!globalPolicy.blockedHexSsids && |
| globalPolicy.blockedHexSsids.includes(hexSsid)); |
| } |
| |
| private shouldShowApnRow_(): boolean { |
| return this.isApnRevampEnabled_ && |
| this.isCellular_(this.managedProperties_); |
| } |
| |
| private shouldShowApnList_(): boolean { |
| return !this.isApnRevampEnabled_ && |
| this.isCellular_(this.managedProperties_); |
| } |
| |
| private showConnect_( |
| managedProperties: ManagedProperties|undefined, |
| globalPolicy: GlobalPolicy|undefined, managedNetworkAvailable: boolean, |
| deviceState: OncMojo.DeviceStateProperties|null): boolean { |
| if (!managedProperties) { |
| return false; |
| } |
| |
| if (this.isBlockedByPolicy_( |
| managedProperties, globalPolicy, managedNetworkAvailable)) { |
| return false; |
| } |
| |
| // TODO(lgcheng@) support connect Arc VPN from UI once Android support API |
| // to initiate a VPN session. |
| if (this.isArcVpn_(managedProperties)) { |
| return false; |
| } |
| |
| if (managedProperties.connectionState !== |
| ConnectionStateType.kNotConnected) { |
| return false; |
| } |
| |
| if (deviceState && deviceState.deviceState !== DeviceStateType.kEnabled) { |
| return false; |
| } |
| |
| const isEthernet = managedProperties.type === NetworkType.kEthernet; |
| |
| // Note: Ethernet networks do not have an explicit "Connect" button in the |
| // UI. |
| return OncMojo.isNetworkConnectable(managedProperties) && !isEthernet; |
| } |
| |
| private showDisconnect_(managedProperties: ManagedProperties| |
| undefined): boolean { |
| if (!managedProperties || |
| managedProperties.type === NetworkType.kEthernet) { |
| return false; |
| } |
| return managedProperties.connectionState !== |
| ConnectionStateType.kNotConnected; |
| } |
| |
| private showSignin_(managedProperties: ManagedProperties|undefined): boolean { |
| if (!managedProperties) { |
| return false; |
| } |
| if (OncMojo.connectionStateIsConnected(managedProperties.connectionState) && |
| this.isPortalState_(managedProperties.portalState)) { |
| return true; |
| } |
| return false; |
| } |
| |
| private showForget_(managedProperties: ManagedProperties): boolean { |
| if (!managedProperties || this.isSecondaryUser_) { |
| return false; |
| } |
| const type = managedProperties.type; |
| if (type !== NetworkType.kWiFi && type !== NetworkType.kVPN) { |
| return false; |
| } |
| if (this.isArcVpn_(managedProperties)) { |
| return false; |
| } |
| return !this.isPolicySource(managedProperties.source) && |
| this.isRemembered_(managedProperties); |
| } |
| |
| private showActivate_(managedProperties: ManagedProperties): boolean { |
| if (!managedProperties || this.isSecondaryUser_) { |
| return false; |
| } |
| if (!this.isCellular_(managedProperties)) { |
| return false; |
| } |
| |
| // Only show the Activate button for unactivated pSIM networks. |
| if (managedProperties.typeProperties.cellular!.eid) { |
| return false; |
| } |
| |
| const activation = |
| managedProperties.typeProperties.cellular!.activationState; |
| return activation === ActivationStateType.kNotActivated || |
| activation === ActivationStateType.kPartiallyActivated; |
| } |
| |
| private showConfigure_( |
| managedProperties: ManagedProperties, globalPolicy: GlobalPolicy, |
| managedNetworkAvailable: boolean): boolean { |
| if (!managedProperties || this.isSecondaryUser_) { |
| return false; |
| } |
| if (this.isBlockedByPolicy_( |
| managedProperties, globalPolicy, managedNetworkAvailable)) { |
| return false; |
| } |
| const type = managedProperties.type; |
| if (type === NetworkType.kCellular || type === NetworkType.kTether) { |
| return false; |
| } |
| if (type === NetworkType.kWiFi && |
| managedProperties.typeProperties.wifi!.security === |
| SecurityType.kNone) { |
| return false; |
| } |
| if (type === NetworkType.kWiFi && |
| (managedProperties.connectionState !== |
| ConnectionStateType.kNotConnected)) { |
| return false; |
| } |
| if (this.isArcVpn_(managedProperties) && |
| !this.isConnectedState_(managedProperties)) { |
| return false; |
| } |
| return true; |
| } |
| |
| private disableSignin_(managedProperties: ManagedProperties| |
| undefined): boolean { |
| if (this.disabled_ || !managedProperties) { |
| return true; |
| } |
| if (!OncMojo.connectionStateIsConnected( |
| managedProperties.connectionState)) { |
| return true; |
| } |
| return !this.isPortalState_(managedProperties.portalState); |
| } |
| |
| |
| private disableForget_( |
| managedProperties: ManagedProperties|undefined, |
| vpnConfigAllowed: chrome.settingsPrivate.PrefObject<boolean>): boolean { |
| if (this.disabled_ || !managedProperties) { |
| return true; |
| } |
| return managedProperties.type === NetworkType.kVPN && vpnConfigAllowed && |
| !vpnConfigAllowed.value; |
| } |
| |
| private disableConfigure_( |
| managedProperties: ManagedProperties|undefined, |
| vpnConfigAllowed: chrome.settingsPrivate.PrefObject<boolean>): boolean { |
| if (this.disabled_ || !managedProperties) { |
| return true; |
| } |
| if (managedProperties.type === NetworkType.kVPN && vpnConfigAllowed && |
| !vpnConfigAllowed.value) { |
| return true; |
| } |
| return this.isPolicySource(managedProperties.source) && |
| !this.hasRecommendedFields_(managedProperties); |
| } |
| |
| private hasRecommendedFields_(managedProperties: ManagedProperties): boolean { |
| if (!managedProperties) { |
| return false; |
| } |
| for (const value of Object.values(managedProperties)) { |
| if (typeof value !== 'object' || value === null) { |
| continue; |
| } |
| if ('activeValue' in value) { |
| if (this.isNetworkPolicyRecommended(value)) { |
| return true; |
| } |
| } else if (this.hasRecommendedFields_(value)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private showViewAccount_(managedProperties: ManagedProperties| |
| undefined): boolean { |
| if (!managedProperties || this.isSecondaryUser_) { |
| return false; |
| } |
| |
| // Show either the 'Activate' or the 'View Account' button (Cellular only). |
| if (!this.isCellular_(managedProperties) || |
| this.showActivate_(managedProperties)) { |
| return false; |
| } |
| |
| // If the network is eSIM, don't show. |
| if (managedProperties.typeProperties.cellular!.eid) { |
| return false; |
| } |
| |
| const paymentPortal = |
| managedProperties.typeProperties.cellular!.paymentPortal; |
| if (!paymentPortal || !paymentPortal.url) { |
| return false; |
| } |
| |
| // Only show for connected networks or LTE networks with a valid MDN. |
| if (!this.isConnectedState_(managedProperties)) { |
| const technology = |
| managedProperties.typeProperties.cellular!.networkTechnology; |
| if (technology !== 'LTE' && technology !== 'LTEAdvanced') { |
| return false; |
| } |
| if (!managedProperties.typeProperties.cellular!.mdn) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| private enableConnect_( |
| managedProperties: ManagedProperties|undefined, |
| defaultNetwork: OncMojo.NetworkStateProperties|null, |
| propertiesReceived: boolean, outOfRange: boolean, |
| globalPolicy: GlobalPolicy|undefined, managedNetworkAvailable: boolean, |
| deviceState: OncMojo.DeviceStateProperties|null): boolean { |
| if (!this.showConnect_( |
| managedProperties, globalPolicy, managedNetworkAvailable, |
| deviceState)) { |
| return false; |
| } |
| |
| if (!propertiesReceived || outOfRange) { |
| return false; |
| } |
| |
| assertExists(managedProperties); |
| if (managedProperties.type === NetworkType.kVPN && !defaultNetwork) { |
| return false; |
| } |
| |
| // Cannot connect to a network which is SIM locked; the user must first |
| // unlock the SIM before attempting a connection. |
| if (managedProperties.type === NetworkType.kCellular && |
| managedProperties.typeProperties.cellular!.simLocked) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| private updateAlwaysOnVpnPrefValue_(): void { |
| this.alwaysOnVpn_.value = this.prefs.arc && this.prefs.arc.vpn && |
| this.prefs.arc.vpn.always_on && this.prefs.arc.vpn.always_on.lockdown && |
| this.prefs.arc.vpn.always_on.lockdown.value; |
| } |
| |
| private getFakeVpnConfigPrefForEnforcement_(): |
| chrome.settingsPrivate.PrefObject<boolean> { |
| const fakeAlwaysOnVpnEnforcementPref: |
| chrome.settingsPrivate.PrefObject<boolean> = { |
| key: 'fakeAlwaysOnPref', |
| type: chrome.settingsPrivate.PrefType.BOOLEAN, |
| value: false, |
| }; |
| // Only mark VPN networks as enforced. This fake pref also controls the |
| // policy indicator on the connect/disconnect buttons, so it shouldn't be |
| // shown on non-VPN networks. |
| if (this.managedProperties_ && |
| this.managedProperties_.type === NetworkType.kVPN && this.prefs && |
| this.prefs.vpn_config_allowed && !this.prefs.vpn_config_allowed.value) { |
| fakeAlwaysOnVpnEnforcementPref.enforcement = |
| chrome.settingsPrivate.Enforcement.ENFORCED; |
| fakeAlwaysOnVpnEnforcementPref.controlledBy = |
| this.prefs.vpn_config_allowed.controlledBy; |
| } |
| return fakeAlwaysOnVpnEnforcementPref; |
| } |
| |
| private updateAlwaysOnVpnPrefEnforcement_(): void { |
| const prefForEnforcement = this.getFakeVpnConfigPrefForEnforcement_(); |
| this.alwaysOnVpn_.enforcement = prefForEnforcement.enforcement; |
| this.alwaysOnVpn_.controlledBy = prefForEnforcement.controlledBy; |
| } |
| |
| private getTetherDialog_(): TetherConnectionDialogElement { |
| return castExists( |
| this.shadowRoot!.querySelector<TetherConnectionDialogElement>( |
| '#tetherDialog')); |
| } |
| |
| private getPasspointRemovalDialog_(): HTMLDialogElement { |
| return castExists(this.shadowRoot!.querySelector<HTMLDialogElement>( |
| '#passpointRemovalDialog')); |
| } |
| |
| private handleConnectClick_(): void { |
| assertExists(this.managedProperties_); |
| if (this.managedProperties_.type === NetworkType.kTether && |
| (!this.managedProperties_.typeProperties.tether!.hasConnectedToHost)) { |
| this.showTetherDialog_(); |
| return; |
| } |
| this.fireNetworkConnect_(/*bypassDialog=*/ false); |
| } |
| |
| private onTetherConnect_(): void { |
| this.getTetherDialog_().close(); |
| this.fireNetworkConnect_(/*bypassDialog=*/ true); |
| } |
| |
| private fireNetworkConnect_(bypassDialog: boolean): void { |
| assertExists(this.managedProperties_); |
| const networkState = |
| OncMojo.managedPropertiesToNetworkState(this.managedProperties_); |
| const networkConnectEvent = new CustomEvent('network-connect', { |
| bubbles: true, |
| composed: true, |
| detail: |
| {networkState: networkState, bypassConnectionDialog: bypassDialog}, |
| }); |
| this.dispatchEvent(networkConnectEvent); |
| recordSettingChange(); |
| } |
| |
| private async handleDisconnectClick_(): Promise<void> { |
| recordSettingChange(); |
| const response = await this.networkConfig_.startDisconnect(this.guid); |
| if (!response.success) { |
| console.warn('Disconnect failed for: ' + this.guid); |
| } |
| } |
| |
| private onConnectDisconnectClick_(): void { |
| if (this.enableConnect_( |
| this.managedProperties_, this.defaultNetwork, |
| this.propertiesReceived_, this.outOfRange_, this.globalPolicy, |
| this.managedNetworkAvailable, this.deviceState_)) { |
| this.handleConnectClick_(); |
| return; |
| } |
| |
| if (this.showDisconnect_(this.managedProperties_)) { |
| this.handleDisconnectClick_(); |
| return; |
| } |
| } |
| |
| private shouldConnectDisconnectButtonBeHidden_(): boolean { |
| return !this.showConnect_( |
| this.managedProperties_, this.globalPolicy, |
| this.managedNetworkAvailable, this.deviceState_) && |
| !this.showDisconnect_(this.managedProperties_); |
| } |
| |
| private shouldConnectDisconnectButtonBeDisabled_(): boolean { |
| if (this.disabled_) { |
| return true; |
| } |
| if (this.enableConnect_( |
| this.managedProperties_, this.defaultNetwork, |
| this.propertiesReceived_, this.outOfRange_, this.globalPolicy, |
| this.managedNetworkAvailable, this.deviceState_)) { |
| return false; |
| } |
| if (this.showDisconnect_(this.managedProperties_)) { |
| return false; |
| } |
| return true; |
| } |
| |
| private getConnectDisconnectButtonLabel_(): string { |
| if (this.showConnect_( |
| this.managedProperties_, this.globalPolicy, |
| this.managedNetworkAvailable, this.deviceState_)) { |
| return this.i18n('networkButtonConnect'); |
| } |
| |
| if (this.showDisconnect_(this.managedProperties_)) { |
| return this.i18n('networkButtonDisconnect'); |
| } |
| |
| return ''; |
| } |
| |
| private async onForgetClick_(): Promise<void> { |
| if (this.isPasspointWifi_(this.managedProperties_)) { |
| // Ask user confirmation before removing a Passpoint Wi-Fi and the |
| // associated subscription. |
| this.getPasspointRemovalDialog_().showModal(); |
| return; |
| } |
| return this.forgetNetwork_(); |
| } |
| |
| private async forgetNetwork_(): Promise<void> { |
| if (this.managedProperties_!.type === NetworkType.kWiFi) { |
| recordSettingChange(Setting.kForgetWifiNetwork); |
| } else { |
| recordSettingChange(); |
| } |
| |
| const response = await this.networkConfig_.forgetNetwork(this.guid); |
| if (!response.success) { |
| console.warn('Forget network failed for: ' + this.guid); |
| } |
| // A forgotten network no longer has a valid GUID, close the subpage. |
| this.close(); |
| } |
| |
| private onSigninClick_(): void { |
| this.browserProxy_.showPortalSignin(this.guid); |
| } |
| |
| private onActivateClick_(): void { |
| this.browserProxy_.showCellularSetupUi(this.guid); |
| } |
| |
| private onConfigureClick_(): void { |
| if (this.managedProperties_ && |
| (this.isThirdPartyVpn_(this.managedProperties_) || |
| this.isArcVpn_(this.managedProperties_))) { |
| this.browserProxy_.configureThirdPartyVpn(this.guid); |
| recordSettingChange(); |
| return; |
| } |
| |
| assertExists(this.managedProperties_); |
| const showConfigEvent = new CustomEvent('show-config', { |
| bubbles: true, |
| composed: true, |
| detail: { |
| guid: this.guid, |
| type: OncMojo.getNetworkTypeString(this.managedProperties_.type), |
| name: OncMojo.getNetworkName(this.managedProperties_), |
| }, |
| }); |
| this.dispatchEvent(showConfigEvent); |
| } |
| |
| private onViewAccountClick_(): void { |
| this.browserProxy_.showCarrierAccountDetail(this.guid); |
| } |
| |
| private showTetherDialog_(): void { |
| this.getTetherDialog_().open(); |
| } |
| |
| private showHiddenNetworkWarning_(): boolean { |
| return loadTimeData.getBoolean('showHiddenNetworkWarning') && |
| !!this.autoConnectPref_.value && !!this.managedProperties_ && |
| this.managedProperties_.type === NetworkType.kWiFi && |
| !!OncMojo.getActiveValue( |
| this.managedProperties_.typeProperties.wifi!.hiddenSsid); |
| } |
| |
| /** |
| * Event triggered for elements associated with network properties. |
| */ |
| private onNetworkPropertyChange_( |
| e: CustomEvent<{field: string, value: (string|number|boolean|string[])}>): |
| void { |
| if (!this.propertiesReceived_) { |
| return; |
| } |
| const field = e.detail.field; |
| const value = e.detail.value; |
| const config = this.getDefaultConfigProperties_(); |
| const valueType = typeof value; |
| if (valueType !== 'string' && valueType !== 'number' && |
| valueType !== 'boolean' && !Array.isArray(value)) { |
| console.warn( |
| 'Unexpected property change event, Key: ' + field + |
| ' Value: ' + JSON.stringify(value)); |
| return; |
| } |
| OncMojo.setConfigProperty(config, field, value); |
| // Ensure that any required configuration properties for partial |
| // configurations are set. |
| const vpnConfig = config.typeConfig.vpn; |
| if (vpnConfig) { |
| if (vpnConfig.openVpn && |
| vpnConfig.openVpn.saveCredentials === undefined) { |
| vpnConfig.openVpn.saveCredentials = false; |
| } |
| if (vpnConfig.l2tp && vpnConfig.l2tp.saveCredentials === undefined) { |
| vpnConfig.l2tp.saveCredentials = false; |
| } |
| } |
| this.setMojoNetworkProperties_(config); |
| } |
| |
| private onApnChange_(event: CustomEvent<ApnProperties>): void { |
| if (!this.propertiesReceived_) { |
| return; |
| } |
| const config = this.getDefaultConfigProperties_(); |
| const apn = event.detail; |
| config.typeConfig.cellular = {apn, roaming: undefined}; |
| this.setMojoNetworkProperties_(config); |
| } |
| |
| private getApnRowSubLabel_(): string { |
| if (!this.isCellular_(this.managedProperties_) || |
| !this.managedProperties_!.typeProperties.cellular!.connectedApn) { |
| return ''; |
| } |
| |
| return this.managedProperties_!.typeProperties.cellular!.connectedApn |
| .accessPointName; |
| } |
| |
| |
| private onApnRowClicked_(): void { |
| if (!this.isCellular_(this.managedProperties_)) { |
| console.error( |
| 'APN row should only be visible when cellular is available.'); |
| return; |
| } |
| const params = new URLSearchParams(); |
| params.append('guid', this.guid); |
| Router.getInstance().navigateTo(routes.APN, params); |
| } |
| |
| /** |
| * Event triggered when the IP Config or NameServers element changes. |
| */ |
| private onIpConfigChange_( |
| event: CustomEvent< |
| {field: string, value: (string|IPConfigProperties|string[])}>): void { |
| if (!this.managedProperties_) { |
| return; |
| } |
| const config = OncMojo.getUpdatedIPConfigProperties( |
| this.managedProperties_, event.detail.field, event.detail.value); |
| if (config) { |
| this.setMojoNetworkProperties_(config); |
| } |
| } |
| |
| /** |
| * Event triggered when the Proxy configuration element changes. |
| */ |
| private onProxyChange_(event: CustomEvent<ProxySettings>): void { |
| if (!this.propertiesReceived_) { |
| return; |
| } |
| const config = this.getDefaultConfigProperties_(); |
| config.proxySettings = event.detail; |
| this.setMojoNetworkProperties_(config); |
| } |
| |
| private propertiesMissingOrBlockedByPolicy_(): boolean { |
| return !this.managedProperties_ || |
| this.isBlockedByPolicy_( |
| this.managedProperties_, this.globalPolicy, |
| this.managedNetworkAvailable); |
| } |
| |
| private sharedString_(managedProperties: ManagedProperties): string { |
| if (!managedProperties.typeProperties.wifi) { |
| return this.i18n('networkShared'); |
| } else if (managedProperties.typeProperties.wifi.isConfiguredByActiveUser) { |
| return this.i18n('networkSharedOwner'); |
| } else { |
| return this.i18n('networkSharedNotOwner'); |
| } |
| } |
| |
| private syncedString_(managedProperties: ManagedProperties): string { |
| if (!managedProperties.typeProperties.wifi) { |
| return ''; |
| } else if (!managedProperties.typeProperties.wifi.isSyncable) { |
| return this.i18nAdvanced('networkNotSynced').toString(); |
| } else if (managedProperties.source === OncSource.kUser) { |
| return this.i18nAdvanced('networkSyncedUser').toString(); |
| } else { |
| return this.i18nAdvanced('networkSyncedDevice').toString(); |
| } |
| } |
| |
| /** |
| * @return Returns 'continuation' class for shared networks. |
| */ |
| private messagesDividerClass_( |
| name: string, managedProperties: ManagedProperties, |
| globalPolicy: GlobalPolicy, managedNetworkAvailable: boolean, |
| isSecondaryUser: boolean, isWifiSyncEnabled: boolean): string { |
| let first = ''; |
| if (this.isBlockedByPolicy_( |
| managedProperties, globalPolicy, managedNetworkAvailable)) { |
| first = 'policy'; |
| } else if (isSecondaryUser) { |
| first = 'secondary'; |
| } else if (this.showShared_( |
| managedProperties, globalPolicy, managedNetworkAvailable)) { |
| first = 'shared'; |
| } else if (this.showSynced_( |
| managedProperties, globalPolicy, managedNetworkAvailable, |
| isWifiSyncEnabled)) { |
| first = 'synced'; |
| } |
| return first === name ? 'continuation' : ''; |
| } |
| |
| private showSynced_( |
| managedProperties: ManagedProperties, _globalPolicy: GlobalPolicy, |
| _managedNetworkAvailable: boolean, isWifiSyncEnabled: boolean): boolean { |
| return !this.propertiesMissingOrBlockedByPolicy_() && isWifiSyncEnabled && |
| !!managedProperties.typeProperties.wifi; |
| } |
| |
| private showShared_( |
| managedProperties: ManagedProperties, _globalPolicy: GlobalPolicy, |
| _managedNetworkAvailable: boolean): boolean { |
| return !this.propertiesMissingOrBlockedByPolicy_() && |
| (managedProperties.source === OncSource.kDevice || |
| managedProperties.source === OncSource.kDevicePolicy); |
| } |
| |
| private showAutoConnect_( |
| managedProperties: ManagedProperties, globalPolicy: GlobalPolicy, |
| managedNetworkAvailable: boolean): boolean { |
| return !!managedProperties && |
| managedProperties.type !== NetworkType.kEthernet && |
| this.isRemembered_(managedProperties) && |
| !this.isArcVpn_(managedProperties) && |
| !this.isBlockedByPolicy_( |
| managedProperties, globalPolicy, managedNetworkAvailable); |
| } |
| |
| private showHiddenNetwork_(): boolean { |
| if (!this.showHiddenToggle_) { |
| return false; |
| } |
| |
| if (!this.managedProperties_) { |
| return false; |
| } |
| |
| if (this.managedProperties_.type !== NetworkType.kWiFi) { |
| return false; |
| } |
| |
| if (!this.isRemembered_(this.managedProperties_)) { |
| return false; |
| } |
| |
| if (this.isBlockedByPolicy_( |
| this.managedProperties_, this.globalPolicy, |
| this.managedNetworkAvailable)) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| private showHiddenNetworkToggleLegacy_(): boolean { |
| return this.showHiddenNetwork_() && !this.enableHiddenNetworkMigration_; |
| } |
| |
| private showHiddenNetworkToggleMoved_(): boolean { |
| return this.showHiddenNetwork_() && this.enableHiddenNetworkMigration_; |
| } |
| |
| private showMetered_(): boolean { |
| const managedProperties = this.managedProperties_; |
| return this.showMeteredToggle_ && !!managedProperties && |
| this.isRemembered_(managedProperties) && |
| (managedProperties.type === NetworkType.kCellular || |
| managedProperties.type === NetworkType.kWiFi); |
| } |
| |
| private showAlwaysOnVpn_(managedProperties: ManagedProperties): boolean { |
| return this.isArcVpn_(managedProperties) && this.prefs.arc && |
| this.prefs.arc.vpn && this.prefs.arc.vpn.always_on && |
| this.prefs.arc.vpn.always_on.vpn_package && |
| OncMojo.getActiveValue(managedProperties.typeProperties.vpn!.host) === |
| this.prefs.arc.vpn.always_on.vpn_package.value; |
| } |
| |
| private alwaysOnVpnChanged_(): void { |
| if (this.prefs && this.prefs.arc && this.prefs.arc.vpn && |
| this.prefs.arc.vpn.always_on && this.prefs.arc.vpn.always_on.lockdown) { |
| this.set( |
| 'prefs.arc.vpn.always_on.lockdown.value', this.alwaysOnVpn_.value); |
| } |
| } |
| |
| private showPreferNetwork_( |
| managedProperties: ManagedProperties, globalPolicy: GlobalPolicy, |
| managedNetworkAvailable: boolean): boolean { |
| if (!managedProperties) { |
| return false; |
| } |
| |
| const type = managedProperties.type; |
| if (type === NetworkType.kEthernet || type === NetworkType.kCellular || |
| this.isArcVpn_(managedProperties)) { |
| return false; |
| } |
| |
| return this.isRemembered_(managedProperties) && |
| !this.isBlockedByPolicy_( |
| managedProperties, globalPolicy, managedNetworkAvailable); |
| } |
| |
| private shouldPreferNetworkToggleBeDisabled_(): boolean { |
| return this.disabled_ || |
| this.isNetworkPolicyEnforced(this.managedProperties_!.priority); |
| } |
| |
| private onPreferNetworkRowClicked_(event: Event): void { |
| // Stop propagation because the toggle and policy indicator handle clicks |
| // themselves. |
| event.stopPropagation(); |
| const preferNetworkToggle = |
| this.shadowRoot!.querySelector<CrToggleElement>('#preferNetworkToggle'); |
| if (!preferNetworkToggle || preferNetworkToggle.disabled) { |
| return; |
| } |
| this.preferNetwork_ = !this.preferNetwork_; |
| } |
| |
| private hasVisibleFields_(fields: string[]): boolean { |
| for (let i = 0; i < fields.length; ++i) { |
| const key = OncMojo.getManagedPropertyKey(fields[i]); |
| const value = this.get(key, this.managedProperties_); |
| if (value !== undefined && value !== null && value !== '') { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private hasInfoFields_(): boolean { |
| const editFieldTypes = this.getInfoEditFieldTypes_(); |
| const infoFields = this.getInfoFields_(); |
| return Object.keys(editFieldTypes).length > 0 || |
| this.hasVisibleFields_(infoFields); |
| } |
| |
| private getInfoFields_(): string[] { |
| if (!this.managedProperties_) { |
| return []; |
| } |
| |
| const fields: string[] = []; |
| switch (this.managedProperties_.type) { |
| case NetworkType.kCellular: |
| fields.push('cellular.servingOperator.name'); |
| break; |
| case NetworkType.kTether: |
| fields.push( |
| 'tether.batteryPercentage', 'tether.signalStrength', |
| 'tether.carrier'); |
| break; |
| case NetworkType.kVPN: |
| const vpnType = this.managedProperties_.typeProperties.vpn!.type; |
| switch (vpnType) { |
| case VpnType.kExtension: |
| fields.push('vpn.providerName'); |
| break; |
| case VpnType.kArc: |
| fields.push('vpn.type'); |
| fields.push('vpn.providerName'); |
| break; |
| case VpnType.kOpenVPN: |
| fields.push( |
| 'vpn.type', 'vpn.host', 'vpn.openVpn.username', |
| 'vpn.openVpn.extraHosts'); |
| break; |
| case VpnType.kL2TPIPsec: |
| fields.push('vpn.type', 'vpn.host', 'vpn.l2tp.username'); |
| break; |
| } |
| break; |
| case NetworkType.kWiFi: |
| break; |
| } |
| if (OncMojo.isRestrictedConnectivity(this.managedProperties_.portalState)) { |
| fields.push('portalState'); |
| } |
| return fields; |
| } |
| |
| /** |
| * Provides the list of editable fields to <network-property-list>. |
| * NOTE: Entries added to this list must be reflected in ConfigProperties in |
| * chromeos.network_config.mojom and handled in the service implementation. |
| * @return A dictionary of editable fields in the info section. |
| */ |
| private getInfoEditFieldTypes_(): |
| Record<string, 'String'|'StringArray'|'Password'> { |
| if (!this.managedProperties_) { |
| return {}; |
| } |
| |
| const editFields: Record<string, 'String'|'StringArray'|'Password'> = {}; |
| const type = this.managedProperties_.type; |
| if (type === NetworkType.kVPN) { |
| const vpnType = this.managedProperties_.typeProperties.vpn!.type; |
| if (vpnType !== VpnType.kExtension) { |
| editFields['vpn.host'] = 'String'; |
| } |
| if (vpnType === VpnType.kOpenVPN) { |
| editFields['vpn.openVpn.username'] = 'String'; |
| editFields['vpn.openVpn.extraHosts'] = 'StringArray'; |
| } |
| } |
| return editFields; |
| } |
| |
| private getAdvancedFields_(): string[] { |
| if (!this.managedProperties_) { |
| return []; |
| } |
| |
| const fields: string[] = []; |
| const type = this.managedProperties_.type; |
| switch (type) { |
| case NetworkType.kCellular: |
| fields.push('cellular.activationState', 'cellular.networkTechnology'); |
| break; |
| case NetworkType.kWiFi: |
| fields.push( |
| 'wifi.ssid', 'wifi.bssid', 'wifi.signalStrength', 'wifi.security', |
| 'wifi.eap.outer', 'wifi.eap.inner', 'wifi.eap.domainSuffixMatch', |
| 'wifi.eap.subjectAltNameMatch', 'wifi.eap.subjectMatch', |
| 'wifi.eap.identity', 'wifi.eap.anonymousIdentity', |
| 'wifi.frequency'); |
| break; |
| case NetworkType.kVPN: |
| const vpnType = this.managedProperties_.typeProperties.vpn!.type; |
| switch (vpnType) { |
| case VpnType.kOpenVPN: |
| if (this.isManagedByPolicy_()) { |
| fields.push( |
| 'vpn.openVpn.auth', 'vpn.openVpn.cipher', |
| 'vpn.openVpn.compressionAlgorithm', |
| 'vpn.openVpn.tlsAuthContents', 'vpn.openVpn.keyDirection'); |
| } |
| break; |
| } |
| break; |
| } |
| return fields; |
| } |
| |
| private getDeviceFields_(): string[] { |
| if (!this.managedProperties_ || |
| this.managedProperties_.type !== NetworkType.kCellular) { |
| return []; |
| } |
| |
| const fields: string[] = []; |
| const networkState = |
| OncMojo.managedPropertiesToNetworkState(this.managedProperties_); |
| if (isActiveSim(networkState, this.deviceState_)) { |
| // These fields are only known for the SIM in the active slot. |
| fields.push( |
| 'cellular.homeProvider.name', 'cellular.homeProvider.country'); |
| } |
| fields.push( |
| 'cellular.firmwareRevision', 'cellular.hardwareRevision', |
| 'cellular.esn', 'cellular.iccid', 'cellular.imei', 'cellular.meid', |
| 'cellular.min'); |
| |
| return fields; |
| } |
| |
| private showDataUsage_(managedProperties: ManagedProperties| |
| undefined): boolean { |
| if (!this.isTrafficCountersEnabled_) { |
| return false; |
| } |
| return !!managedProperties && this.guid !== '' && |
| this.isCellular_(managedProperties) && |
| this.isConnectedState_(managedProperties); |
| } |
| |
| private hasAdvancedSection_(): boolean { |
| if (!this.managedProperties_ || !this.propertiesReceived_) { |
| return false; |
| } |
| if (this.showMetered_()) { |
| return true; |
| } |
| if (this.managedProperties_.type === NetworkType.kTether) { |
| // These properties apply to the underlying WiFi network, not the Tether |
| // network. |
| return false; |
| } |
| return this.hasAdvancedFields_() || this.hasDeviceFields_(); |
| } |
| |
| private hasAdvancedFields_(): boolean { |
| return this.hasVisibleFields_(this.getAdvancedFields_()); |
| } |
| |
| private hasDeviceFields_(): boolean { |
| return this.hasVisibleFields_(this.getDeviceFields_()); |
| } |
| |
| private hasNetworkSection_( |
| managedProperties: ManagedProperties, globalPolicy: GlobalPolicy, |
| managedNetworkAvailable: boolean): boolean { |
| if (!managedProperties || managedProperties.type === NetworkType.kTether) { |
| // These settings apply to the underlying WiFi network, not the Tether |
| // network. |
| return false; |
| } |
| if (this.isBlockedByPolicy_( |
| managedProperties, globalPolicy, managedNetworkAvailable)) { |
| return false; |
| } |
| if (managedProperties.type === NetworkType.kCellular) { |
| return true; |
| } |
| return this.isRememberedOrConnected_(managedProperties); |
| } |
| |
| private hasProxySection_( |
| managedProperties: ManagedProperties, globalPolicy: GlobalPolicy, |
| managedNetworkAvailable: boolean): boolean { |
| if (!managedProperties || managedProperties.type === NetworkType.kTether) { |
| // Proxy settings apply to the underlying WiFi network, not the Tether |
| // network. |
| return false; |
| } |
| if (this.isBlockedByPolicy_( |
| managedProperties, globalPolicy, managedNetworkAvailable)) { |
| return false; |
| } |
| return this.isRememberedOrConnected_(managedProperties); |
| } |
| |
| private isPasspointWifi_(managedProperties: ManagedProperties| |
| undefined): boolean { |
| if (!this.isPasspointEnabled_) { |
| return false; |
| } |
| return !!managedProperties && |
| managedProperties.type === NetworkType.kWiFi && |
| managedProperties.typeProperties.wifi!.passpointId !== '' && |
| managedProperties.typeProperties.wifi!.passpointMatchType !== |
| MatchType.kNoMatch; |
| } |
| |
| private shouldShowPasspointProviderRow_(managedProperties: ManagedProperties| |
| undefined): boolean { |
| return this.isPasspointSettingsEnabled_ && |
| this.isPasspointWifi_(managedProperties); |
| } |
| |
| private getPasspointSubscriptionName_(subscription: PasspointSubscription| |
| null): string { |
| if (!subscription) { |
| return ''; |
| } |
| if (subscription.friendlyName && subscription.friendlyName !== '') { |
| return subscription.friendlyName; |
| } |
| return subscription.domains[0]; |
| } |
| |
| private onPasspointRowClicked_(): void { |
| const showPasspointEvent = new CustomEvent( |
| 'show-passpoint-detail', |
| {bubbles: true, composed: true, detail: this.passpointSubscription_}); |
| this.dispatchEvent(showPasspointEvent); |
| } |
| |
| private onPasspointRemovalDialogCancel_(): void { |
| this.getPasspointRemovalDialog_().close(); |
| } |
| |
| private onPasspointRemovalDialogConfirm_(): void { |
| this.getPasspointRemovalDialog_().close(); |
| this.forgetNetwork_(); |
| } |
| |
| private showCellularChooseNetwork_(managedProperties: ManagedProperties): |
| boolean { |
| return !!managedProperties && |
| managedProperties.type === NetworkType.kCellular && |
| managedProperties.typeProperties.cellular!.supportNetworkScan; |
| } |
| |
| private showScanningSpinner_(): boolean { |
| if (!this.managedProperties_ || |
| this.managedProperties_.type !== NetworkType.kCellular) { |
| return false; |
| } |
| return !!this.deviceState_ && this.deviceState_.scanning; |
| } |
| |
| private showCellularSimUpdatedUi_(managedProperties: ManagedProperties): |
| boolean { |
| return !!managedProperties && |
| managedProperties.type === NetworkType.kCellular && |
| managedProperties.typeProperties.cellular!.family !== 'CDMA'; |
| } |
| |
| private isArcVpn_(managedProperties: ManagedProperties|undefined): boolean { |
| return !!managedProperties && managedProperties.type === NetworkType.kVPN && |
| managedProperties.typeProperties.vpn!.type === VpnType.kArc; |
| } |
| |
| private isThirdPartyVpn_(managedProperties: ManagedProperties| |
| undefined): boolean { |
| return !!managedProperties && managedProperties.type === NetworkType.kVPN && |
| managedProperties.typeProperties.vpn!.type === VpnType.kExtension; |
| } |
| |
| private showIpAddress_( |
| ipAddress: string, managedProperties: ManagedProperties): boolean { |
| // Arc Vpn does not currently pass IP configuration to ChromeOS. IP address |
| // property holds an internal IP address Android uses to talk to ChromeOS. |
| // TODO(lgcheng@) Show correct IP address when we implement IP configuration |
| // correctly. |
| if (this.isArcVpn_(managedProperties)) { |
| return false; |
| } |
| |
| // Cellular IP addresses are shown under the network details section. |
| if (this.isCellular_(managedProperties)) { |
| return false; |
| } |
| |
| return !!ipAddress && this.isConnectedState_(managedProperties); |
| } |
| |
| private isOutOfRangeOrNotEnabled_( |
| outOfRange: boolean, |
| deviceState: OncMojo.DeviceStateProperties|null): boolean { |
| return outOfRange || |
| (!!deviceState && deviceState.deviceState !== DeviceStateType.kEnabled); |
| } |
| |
| private computeShowConfigurableSections_(): boolean { |
| if (!this.managedProperties_ || !this.deviceState_) { |
| return true; |
| } |
| |
| const networkState = |
| OncMojo.managedPropertiesToNetworkState(this.managedProperties_); |
| assertExists(networkState); |
| if (networkState.type !== NetworkType.kCellular) { |
| return true; |
| } |
| return isActiveSim(networkState, this.deviceState_); |
| } |
| |
| private computeDisabled_(): boolean { |
| if (!this.deviceState_ || |
| this.deviceState_.type !== NetworkType.kCellular) { |
| return false; |
| } |
| // If this is a cellular device and inhibited, state cannot be changed, so |
| // the page's inputs should be disabled. |
| return OncMojo.deviceIsInhibited(this.deviceState_); |
| } |
| |
| private shouldShowMacAddress_(): boolean { |
| return !!this.getMacAddress_(); |
| } |
| |
| private getMacAddress_(): string { |
| if (!this.deviceState_) { |
| return ''; |
| } |
| |
| // 00:00:00:00:00:00 is provided when device MAC address cannot be |
| // retrieved. |
| const MISSING_MAC_ADDRESS = '00:00:00:00:00:00'; |
| if (this.deviceState_ && this.deviceState_.macAddress && |
| this.deviceState_.macAddress !== MISSING_MAC_ADDRESS) { |
| return this.deviceState_.macAddress; |
| } |
| |
| return ''; |
| } |
| |
| private isManagedByPolicy_(): boolean { |
| return this.managedProperties_!.source === OncSource.kUserPolicy || |
| this.managedProperties_!.source === OncSource.kDevicePolicy; |
| } |
| |
| private isPortalState_(portalState: PortalState): boolean { |
| return portalState === PortalState.kPortal || |
| portalState === PortalState.kProxyAuthRequired; |
| } |
| } |
| |
| declare global { |
| interface HTMLElementTagNameMap { |
| [SettingsInternetDetailPageElement.is]: SettingsInternetDetailPageElement; |
| } |
| } |
| |
| customElements.define( |
| SettingsInternetDetailPageElement.is, SettingsInternetDetailPageElement); |