// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import '//resources/polymer/v3_0/iron-pages/iron-pages.js';
import './setup_loading_page.js';
import './activation_code_page.js';
import './activation_verification_page.js';
import './final_page.js';
import './profile_discovery_consent_page.js';
import './profile_discovery_list_page.js';
import './confirmation_code_page.js';
import {I18nMixin} from '//resources/ash/common/cr_elements/i18n_mixin.js';
import {hasActiveCellularNetwork} from '//resources/ash/common/network/cellular_utils.js';
import {MojoInterfaceProviderImpl} from '//resources/ash/common/network/mojo_interface_provider.js';
import {NetworkListenerBehavior} from '//resources/ash/common/network/network_listener_behavior.js';
import {assert, assertNotReached} from '//resources/js/assert.js';
import {ESimManagerInterface, ESimOperationResult, ESimProfileProperties, EuiccRemote, ProfileInstallMethod, ProfileInstallResult, ProfileState} from '//resources/mojo/chromeos/ash/services/cellular_setup/public/mojom/esim_manager.mojom-webui.js';
import {FilterType, NetworkStateProperties, NO_LIMIT} from '//resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js';
import {ConnectionStateType, NetworkType} from '//resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js';
import {mixinBehaviors, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {ActivationCodePageElement} from './activation_code_page.js';
import {CellularSetupDelegate} from './cellular_setup_delegate.js';
import {ButtonBarState, ButtonState} from './cellular_types.js';
import {getTemplate} from './esim_flow_ui.html.js';
import {getEuicc} from './esim_manager_utils.js';
import {getESimManagerRemote} from './mojo_interface_provider.js';
import {ProfileDiscoveryListPageElement} from './profile_discovery_list_page.js';
import {SubflowMixin} from './subflow_mixin.js';
export enum EsimPageName {
PROFILE_LOADING = 'profileLoadingPage',
PROFILE_DISCOVERY_CONSENT = 'profileDiscoveryConsentPage',
PROFILE_DISCOVERY = 'profileDiscoveryPage',
ACTIVATION_CODE = 'activationCodePage',
CONFIRMATION_CODE = 'confirmationCodePage',
PROFILE_INSTALLING = 'profileInstallingPage',
FINAL = 'finalPage',
}
export enum EsimUiState {
PROFILE_SEARCH = 'profile-search',
PROFILE_SEARCH_CONSENT = 'profile-search-consent',
ACTIVATION_CODE_ENTRY = 'activation-code-entry',
ACTIVATION_CODE_ENTRY_READY = 'activation-code-entry-ready',
ACTIVATION_CODE_ENTRY_INSTALLING = 'activation-code-entry-installing',
CONFIRMATION_CODE_ENTRY = 'confirmation-code-entry',
CONFIRMATION_CODE_ENTRY_READY = 'confirmation-code-entry-ready',
CONFIRMATION_CODE_ENTRY_INSTALLING = 'confirmation-code-entry-installing',
PROFILE_SELECTION = 'profile-selection',
PROFILE_SELECTION_INSTALLING = 'profile-selection-installing',
SETUP_FINISH = 'setup-finish',
}
// The reason that caused the user to exit the ESim Setup flow.
// These values are persisted to logs. Entries should not be renumbered
// and numeric values should never be reused.
export enum EsimSetupFlowResult {
SUCCESS = 0,
INSTALL_FAIL = 1,
CANCELLED_NEEDS_CONFIRMATION_CODE = 2,
CANCELLED_INVALID_ACTIVATION_CODE = 3,
ERROR_FETCHING_PROFILES = 4,
CANCELLED_WITHOUT_ERROR = 5,
CANCELLED_NO_PROFILES = 6,
NO_NETWORK = 7,
}
export const ESIM_SETUP_RESULT_METRIC_NAME =
'Network.Cellular.ESim.SetupFlowResult';
export const SUCCESSFUL_ESIM_SETUP_DURATION_METRIC_NAME =
'Network.Cellular.ESim.CellularSetup.Success.Duration';
export const FAILED_ESIM_SETUP_DURATION_METRIC_NAME =
'Network.Cellular.ESim.CellularSetup.Failure.Duration';
declare global {
interface HTMLElementEventMap {
'activation-code-updated':
CustomEvent<{activationCode: string|null}>;
}
}
/**
* Root element for the eSIM cellular setup flow. This element interacts with
* the CellularSetup service to carry out the esim activation flow.
*/
const EsimFlowUiElementBase =
mixinBehaviors([NetworkListenerBehavior],
SubflowMixin(I18nMixin(PolymerElement)));
export class EsimFlowUiElement extends EsimFlowUiElementBase {
static get is() {
return 'esim-flow-ui' as const;
}
static get template() {
return getTemplate();
}
static get properties() {
return {
delegate: Object,
/**
* Header shown at the top of the flow. No header shown if the string is
* empty.
*/
header: {
type: String,
notify: true,
computed: 'computeHeader_(selectedEsimPageName_, showError_)',
},
forwardButtonLabel: {
type: String,
notify: true,
},
state_: {
type: String,
value: EsimUiState.PROFILE_SEARCH_CONSENT,
observer: 'onStateChanged_',
},
/**
* Element name of the current selected sub-page.
* This is set in updateSelectedPage_ on initialization.
*/
selectedEsimPageName_: String,
/**
* Whether the user has consented to a scan for profiles.
*/
hasConsentedForDiscovery_: {
type: Boolean,
value: false,
},
/**
* Whether the user is setting up the eSIM profile manually.
*/
shouldSkipDiscovery_: {
type: Boolean,
value: false,
},
/**
* Whether error state should be shown for the current page.
*/
showError_: {
type: Boolean,
value: false,
},
/**
* Profile properties fetched from the latest SM-DS scan.
*/
pendingProfileProperties_: Array,
/**
* Profile properties selected to be installed.
*/
selectedProfileProperties_: {
type: Object,
observer: 'onSelectedProfilePropertiesChanged_',
},
activationCode_: {
type: String,
value: '',
},
confirmationCode_: {
type: String,
value: '',
observer: 'onConfirmationCodeUpdated_',
},
hasHadActiveCellularNetwork_: {
type: Boolean,
value: false,
},
isActivationCodeFromQrCode_: Boolean,
};
}
delegate: CellularSetupDelegate;
header: string;
forwardButtonLabel: string;
private state_: string;
private selectedEsimPageName_: string;
private hasConsentedForDiscovery_: boolean;
private shouldSkipDiscovery_: boolean;
private showError_: boolean;
private pendingProfileProperties_: ESimProfileProperties[];
private selectedProfileProperties_: ESimProfileProperties|null;
private activationCode_: string;
private confirmationCode_: string;
private hasHadActiveCellularNetwork_: boolean;
private isActivationCodeFromQrCode_: boolean;
/**
* Provides an interface to the ESimManager Mojo service.
*/
private eSimManagerRemote_: ESimManagerInterface;
private euicc_: EuiccRemote|null = null;
private lastProfileInstallResult_: ProfileInstallResult|null = null;
private hasFailedFetchingProfiles_: boolean = false;
/**
* If there are no active network connections of any type.
*/
private isOffline_: boolean = false;
/**
* The time at which the ESim flow is attached.
*/
private timeOnAttached_: Date|null = null;
constructor() {
super();
this.eSimManagerRemote_ = getESimManagerRemote();
const networkConfig =
MojoInterfaceProviderImpl.getInstance().getMojoServiceRemote();
const filter = {
filter: FilterType.kActive,
limit: NO_LIMIT,
networkType: NetworkType.kAll,
};
networkConfig.getNetworkStateList(filter).then((response) => {
this.onActiveNetworksChanged(response.result);
});
}
override connectedCallback() {
super.connectedCallback();
this.timeOnAttached_ = new Date();
}
override disconnectedCallback() {
super.disconnectedCallback();
let resultCode = null;
switch (this.lastProfileInstallResult_) {
case null:
// Handles case when no profile installation was attempted.
if (this.hasFailedFetchingProfiles_) {
resultCode = EsimSetupFlowResult.ERROR_FETCHING_PROFILES;
} else if (this.noProfilesFound_()) {
resultCode = EsimSetupFlowResult.CANCELLED_NO_PROFILES;
} else {
resultCode = EsimSetupFlowResult.CANCELLED_WITHOUT_ERROR;
}
break;
case ProfileInstallResult.kSuccess:
resultCode = EsimSetupFlowResult.SUCCESS;
break;
case ProfileInstallResult.kFailure:
resultCode = EsimSetupFlowResult.INSTALL_FAIL;
break;
case ProfileInstallResult.kErrorNeedsConfirmationCode:
resultCode = EsimSetupFlowResult.CANCELLED_NEEDS_CONFIRMATION_CODE;
break;
case ProfileInstallResult.kErrorInvalidActivationCode:
resultCode = EsimSetupFlowResult.CANCELLED_INVALID_ACTIVATION_CODE;
break;
default:
break;
}
if (this.isOffline_ && resultCode !== ProfileInstallResult.kSuccess) {
resultCode = EsimSetupFlowResult.NO_NETWORK;
}
assert(resultCode !== null);
chrome.metricsPrivate.recordEnumerationValue(
ESIM_SETUP_RESULT_METRIC_NAME, resultCode,
Object.keys(EsimSetupFlowResult).length);
const elapsedTimeMs = new Date().getTime() - this.timeOnAttached_!.getTime();
if (resultCode === EsimSetupFlowResult.SUCCESS) {
chrome.metricsPrivate.recordLongTime(
SUCCESSFUL_ESIM_SETUP_DURATION_METRIC_NAME, elapsedTimeMs);
return;
}
chrome.metricsPrivate.recordLongTime(
FAILED_ESIM_SETUP_DURATION_METRIC_NAME, elapsedTimeMs);
}
override ready() {
super.ready();
this.addEventListener('activation-code-updated',
(event: CustomEvent<{activationCode: string|null}>) => {
this.onActivationCodeUpdated_(event);
});
this.addEventListener('forward-navigation-requested',
this.onForwardNavigationRequested_);
}
/**
* NetworkListenerBehavior override
* Used to determine if there is an online network connection.
*/
onActiveNetworksChanged(activeNetworks: NetworkStateProperties[]): void {
this.isOffline_ = !activeNetworks.some(
(network) => network.connectionState === ConnectionStateType.kOnline);
}
override initSubflow(): void {
// Installing an eSIM profile may result in Hermes restarting and losing
// its state. When this happens the cache of profiles used for the UI may
// become corrupted and will not include all installed profiles.
// Explicitly refresh the cache when this dialog is opened to ensure the
// cache is regenerated and valid.
this.refreshInstalledProfiles_();
this.onNetworkStateListChanged();
}
private async fetchProfiles_(): Promise<void> {
await this.getEuicc_();
if (!this.euicc_) {
return;
}
await this.getAvailableProfileProperties_();
if (this.noProfilesFound_()) {
this.state_ = EsimUiState.ACTIVATION_CODE_ENTRY;
} else {
this.state_ = EsimUiState.PROFILE_SELECTION;
}
}
private async getEuicc_(): Promise<void> {
const euicc = await getEuicc();
if (!euicc) {
this.hasFailedFetchingProfiles_ = true;
this.showError_ = true;
this.state_ = EsimUiState.SETUP_FINISH;
console.warn('No Euiccs found');
return;
}
this.euicc_ = euicc;
}
private async getAvailableProfileProperties_(): Promise<void> {
assert(this.euicc_);
const requestAvailableProfilesResponse =
await this.euicc_.requestAvailableProfiles();
if (requestAvailableProfilesResponse.result ===
ESimOperationResult.kFailure) {
this.hasFailedFetchingProfiles_ = true;
console.warn(
'Error requesting available profiles: ',
requestAvailableProfilesResponse);
this.pendingProfileProperties_ = [];
}
this.pendingProfileProperties_ =
requestAvailableProfilesResponse.profiles.filter((properties) => {
return properties.state === ProfileState.kPending &&
properties.activationCode;
});
}
private async refreshInstalledProfiles_(): Promise<void> {
await this.getEuicc_();
if (!this.euicc_) {
return;
}
await this.euicc_.refreshInstalledProfiles();
}
private handleProfileInstallResponse_(
response: {result: ProfileInstallResult}): void {
this.lastProfileInstallResult_ = response.result;
if (response.result === ProfileInstallResult.kErrorNeedsConfirmationCode) {
this.state_ = EsimUiState.CONFIRMATION_CODE_ENTRY;
return;
}
this.showError_ = response.result !== ProfileInstallResult.kSuccess;
if (response.result === ProfileInstallResult.kFailure &&
this.state_ === EsimUiState.CONFIRMATION_CODE_ENTRY_INSTALLING) {
this.state_ = EsimUiState.CONFIRMATION_CODE_ENTRY_READY;
return;
}
if (response.result === ProfileInstallResult.kErrorInvalidActivationCode &&
this.state_ !== EsimUiState.PROFILE_SELECTION_INSTALLING) {
this.state_ = EsimUiState.ACTIVATION_CODE_ENTRY_READY;
return;
}
if (response.result === ProfileInstallResult.kSuccess ||
response.result === ProfileInstallResult.kFailure) {
this.state_ = EsimUiState.SETUP_FINISH;
}
}
private onStateChanged_(newState: EsimUiState, oldState: EsimUiState): void {
this.updateButtonBarState_();
this.updateSelectedPage_();
if (this.hasConsentedForDiscovery_ &&
newState === EsimUiState.PROFILE_SEARCH) {
this.fetchProfiles_();
}
this.initializePageState_(newState, oldState);
}
private updateSelectedPage_(): void {
const oldSelectedEsimPageName = this.selectedEsimPageName_;
switch (this.state_) {
case EsimUiState.PROFILE_SEARCH:
this.selectedEsimPageName_ = EsimPageName.PROFILE_LOADING;
break;
case EsimUiState.PROFILE_SEARCH_CONSENT:
this.selectedEsimPageName_ = EsimPageName.PROFILE_DISCOVERY_CONSENT;
break;
case EsimUiState.ACTIVATION_CODE_ENTRY:
case EsimUiState.ACTIVATION_CODE_ENTRY_READY:
this.selectedEsimPageName_ = EsimPageName.ACTIVATION_CODE;
break;
case EsimUiState.ACTIVATION_CODE_ENTRY_INSTALLING:
this.selectedEsimPageName_ = EsimPageName.PROFILE_INSTALLING;
break;
case EsimUiState.CONFIRMATION_CODE_ENTRY:
case EsimUiState.CONFIRMATION_CODE_ENTRY_READY:
this.selectedEsimPageName_ = EsimPageName.CONFIRMATION_CODE;
break;
case EsimUiState.CONFIRMATION_CODE_ENTRY_INSTALLING:
this.selectedEsimPageName_ = EsimPageName.PROFILE_INSTALLING;
break;
case EsimUiState.PROFILE_SELECTION:
this.selectedEsimPageName_ = EsimPageName.PROFILE_DISCOVERY;
break;
case EsimUiState.PROFILE_SELECTION_INSTALLING:
this.selectedEsimPageName_ = EsimPageName.PROFILE_INSTALLING;
break;
case EsimUiState.SETUP_FINISH:
this.selectedEsimPageName_ = EsimPageName.FINAL;
break;
default:
assertNotReached();
}
// If there is a page change, fire focus event.
if (oldSelectedEsimPageName !== this.selectedEsimPageName_) {
this.dispatchEvent(new CustomEvent('focus-default-button', {
bubbles: true, composed: true,
}));
}
}
private generateButtonStateForActivationPage_(
enableForwardBtn: boolean,
cancelButtonStateIfEnabled: ButtonState): ButtonBarState {
this.forwardButtonLabel = this.i18n('next');
return {
cancel: cancelButtonStateIfEnabled,
forward: enableForwardBtn ? ButtonState.ENABLED : ButtonState.DISABLED,
};
}
private generateButtonStateForConfirmationPage_(
enableForwardBtn: boolean,
cancelButtonStateIfEnabled: ButtonState): ButtonBarState {
this.forwardButtonLabel = this.i18n('confirm');
return {
cancel: cancelButtonStateIfEnabled,
forward: enableForwardBtn ? ButtonState.ENABLED : ButtonState.DISABLED,
};
}
private updateButtonBarState_(): void {
let buttonState;
const cancelButtonStateIfEnabled = this.delegate.shouldShowCancelButton() ?
ButtonState.ENABLED :
ButtonState.HIDDEN;
const cancelButtonStateIfDisabled = this.delegate.shouldShowCancelButton() ?
ButtonState.DISABLED :
ButtonState.HIDDEN;
switch (this.state_) {
case EsimUiState.PROFILE_SEARCH:
this.forwardButtonLabel = this.i18n('next');
buttonState = {
cancel: cancelButtonStateIfEnabled,
forward: ButtonState.DISABLED,
};
break;
case EsimUiState.PROFILE_SEARCH_CONSENT:
this.forwardButtonLabel = this.i18n('profileDiscoveryConsentScan');
buttonState = {
cancel: ButtonState.ENABLED,
forward: ButtonState.ENABLED,
};
break;
case EsimUiState.ACTIVATION_CODE_ENTRY:
buttonState = this.generateButtonStateForActivationPage_(
/*enableForwardBtn*/ false, cancelButtonStateIfEnabled);
break;
case EsimUiState.ACTIVATION_CODE_ENTRY_READY:
buttonState = this.generateButtonStateForActivationPage_(
/*enableForwardBtn*/ true, cancelButtonStateIfEnabled);
break;
case EsimUiState.ACTIVATION_CODE_ENTRY_INSTALLING:
buttonState = this.generateButtonStateForActivationPage_(
/*enableForwardBtn*/ false, cancelButtonStateIfDisabled);
break;
case EsimUiState.CONFIRMATION_CODE_ENTRY:
buttonState = this.generateButtonStateForConfirmationPage_(
/*enableForwardBtn*/ false, cancelButtonStateIfEnabled);
break;
case EsimUiState.CONFIRMATION_CODE_ENTRY_READY:
buttonState = this.generateButtonStateForConfirmationPage_(
/*enableForwardBtn*/ true, cancelButtonStateIfEnabled);
break;
case EsimUiState.CONFIRMATION_CODE_ENTRY_INSTALLING:
buttonState = this.generateButtonStateForConfirmationPage_(
/*enableForwardBtn*/ false, cancelButtonStateIfDisabled);
break;
case EsimUiState.PROFILE_SELECTION:
this.updateForwardButtonLabel_();
buttonState = {
cancel: cancelButtonStateIfEnabled,
forward: ButtonState.ENABLED,
};
break;
case EsimUiState.PROFILE_SELECTION_INSTALLING:
buttonState = {
cancel: cancelButtonStateIfDisabled,
forward: ButtonState.DISABLED,
};
break;
case EsimUiState.SETUP_FINISH:
this.forwardButtonLabel = this.i18n('done');
buttonState = {
cancel: ButtonState.HIDDEN,
forward: ButtonState.ENABLED,
};
break;
default:
assertNotReached();
}
this.set('buttonState', buttonState);
}
private updateForwardButtonLabel_(): void {
this.forwardButtonLabel = this.selectedProfileProperties_ ?
this.i18n('next') :
this.i18n('skipDiscovery');
}
private initializePageState_(newState: EsimUiState, oldState: EsimUiState):
void {
if (newState === EsimUiState.CONFIRMATION_CODE_ENTRY &&
oldState !== EsimUiState.CONFIRMATION_CODE_ENTRY_READY) {
this.confirmationCode_ = '';
}
if (newState === EsimUiState.ACTIVATION_CODE_ENTRY &&
oldState !== EsimUiState.ACTIVATION_CODE_ENTRY_READY) {
this.activationCode_ = '';
}
}
private onActivationCodeUpdated_(event: CustomEvent<{activationCode: string|null}>): void {
// initializePageState_() may cause this observer to fire and update the
// buttonState when we're not on the activation code page. Check we're on
// the activation code page before proceeding.
if (this.state_ !== EsimUiState.ACTIVATION_CODE_ENTRY &&
this.state_ !== EsimUiState.ACTIVATION_CODE_ENTRY_READY) {
return;
}
this.state_ = event.detail.activationCode ?
EsimUiState.ACTIVATION_CODE_ENTRY_READY :
EsimUiState.ACTIVATION_CODE_ENTRY;
}
private onSelectedProfilePropertiesChanged_(): void {
// initializePageState_() may cause this observer to fire and update the
// buttonState when we're not on the profile selection page. Check we're
// on the profile selection page before proceeding.
if (this.state_ !== EsimUiState.PROFILE_SELECTION) {
return;
}
this.updateForwardButtonLabel_();
}
private onConfirmationCodeUpdated_(): void {
// initializePageState_() may cause this observer to fire and update the
// buttonState when we're not on the confirmation code page. Check we're
// on the confirmation code page before proceeding.
if (this.state_ !== EsimUiState.CONFIRMATION_CODE_ENTRY &&
this.state_ !== EsimUiState.CONFIRMATION_CODE_ENTRY_READY) {
return;
}
this.state_ = this.confirmationCode_ ?
EsimUiState.CONFIRMATION_CODE_ENTRY_READY :
EsimUiState.CONFIRMATION_CODE_ENTRY;
}
/** SubflowMixin override */
override navigateForward(): void {
this.showError_ = false;
switch (this.state_) {
case EsimUiState.PROFILE_SEARCH_CONSENT:
if (this.shouldSkipDiscovery_) {
this.state_ = EsimUiState.ACTIVATION_CODE_ENTRY;
break;
}
// Set |this.hasConsentedForDiscovery_| to |true| since navigating
// forward and not setting up manually is explicitly giving consent
// to perform SM-DS scans.
this.hasConsentedForDiscovery_= true;
this.state_ = EsimUiState.PROFILE_SEARCH;
break;
case EsimUiState.ACTIVATION_CODE_ENTRY_READY:
assert(this.euicc_);
// Assume installing the profile doesn't require a confirmation
// code.
const confirmationCode = '';
this.state_ = EsimUiState.ACTIVATION_CODE_ENTRY_INSTALLING;
this.euicc_
.installProfileFromActivationCode(
this.activationCode_, confirmationCode,
this.computeProfileInstallMethod_())
.then(this.handleProfileInstallResponse_.bind(this));
break;
case EsimUiState.PROFILE_SELECTION:
if (this.selectedProfileProperties_) {
assert(this.euicc_);
this.state_ = EsimUiState.PROFILE_SELECTION_INSTALLING;
// Assume installing the profile doesn't require a confirmation
// code.
const confirmationCode = '';
this.euicc_
.installProfileFromActivationCode(
this.selectedProfileProperties_.activationCode,
confirmationCode, ProfileInstallMethod.kViaSmds)
.then(this.handleProfileInstallResponse_.bind(this));
} else {
this.state_ = EsimUiState.ACTIVATION_CODE_ENTRY;
}
break;
case EsimUiState.CONFIRMATION_CODE_ENTRY_READY:
this.state_ = EsimUiState.CONFIRMATION_CODE_ENTRY_INSTALLING;
assert(this.euicc_);
const fromQrCode = this.selectedProfileProperties_ ? true : false;
const activationCode = fromQrCode ?
this.selectedProfileProperties_!.activationCode :
this.activationCode_;
this.euicc_
.installProfileFromActivationCode(
activationCode, this.confirmationCode_,
this.computeProfileInstallMethod_())
.then(this.handleProfileInstallResponse_.bind(this));
break;
case EsimUiState.SETUP_FINISH:
this.dispatchEvent(new CustomEvent('exit-cellular-setup', {
bubbles: true, composed: true,
}));
break;
default:
assertNotReached();
}
}
/** SubflowMixin override */
override maybeFocusPageElement(): boolean {
switch (this.state_) {
case EsimUiState.ACTIVATION_CODE_ENTRY:
case EsimUiState.ACTIVATION_CODE_ENTRY_READY:
const activationCodePage =
this.shadowRoot!.querySelector<ActivationCodePageElement>(
'#activationCodePage');
if (!activationCodePage) {
return false;
}
return activationCodePage!.attemptToFocusOnPageContent();
case EsimUiState.PROFILE_SELECTION:
const profileDiscoveryPage =
this.shadowRoot!.querySelector<ProfileDiscoveryListPageElement>(
'#profileDiscoveryPage');
if (!profileDiscoveryPage) {
return false;
}
return profileDiscoveryPage.attemptToFocusOnFirstProfile();
default:
return false;
}
}
private onForwardNavigationRequested_(): void {
if (this.state_ === EsimUiState.ACTIVATION_CODE_ENTRY_READY ||
this.state_ === EsimUiState.CONFIRMATION_CODE_ENTRY_READY ||
this.state_ === EsimUiState.PROFILE_SEARCH_CONSENT ||
this.state_ === EsimUiState.PROFILE_SELECTION) {
this.navigateForward();
}
}
/** NetworkListenerBehavior override */
async onNetworkStateListChanged(): Promise<void> {
const hasActive = await hasActiveCellularNetwork();
// If hasHadActiveCellularNetwork_ has been set to true, don't set to
// false again as we should show the cellular disconnect warning for the
// duration of the flow's lifecycle.
if (hasActive) {
this.hasHadActiveCellularNetwork_ = hasActive;
}
}
private computeHeader_(): string {
if (this.selectedEsimPageName_ === EsimPageName.FINAL && !this.showError_) {
return this.i18n('eSimFinalPageSuccessHeader');
}
if (this.selectedEsimPageName_ === EsimPageName.PROFILE_DISCOVERY_CONSENT) {
return this.i18n('profileDiscoveryConsentTitle');
}
if (this.selectedEsimPageName_ === EsimPageName.PROFILE_DISCOVERY) {
return this.i18n('profileDiscoveryPageTitle');
}
if (this.selectedEsimPageName_ == EsimPageName.CONFIRMATION_CODE) {
return this.i18n('confimationCodePageTitle');
}
if (this.selectedEsimPageName_ == EsimPageName.PROFILE_LOADING) {
return this.i18n('profileLoadingPageTitle');
}
return '';
}
private computeProfileInstallMethod_(): ProfileInstallMethod {
if (this.isActivationCodeFromQrCode_) {
return this.hasConsentedForDiscovery_ ?
ProfileInstallMethod.kViaQrCodeAfterSmds :
ProfileInstallMethod.kViaQrCodeSkippedSmds;
}
return this.hasConsentedForDiscovery_ ?
ProfileInstallMethod.kViaActivationCodeAfterSmds :
ProfileInstallMethod.kViaActivationCodeSkippedSmds;
}
/**
* Returns true if profiles have been received and none were found.
*/
private noProfilesFound_(): boolean {
return this.hasConsentedForDiscovery_ && !!this.pendingProfileProperties_ &&
this.pendingProfileProperties_.length === 0;
}
private profilesFound_(): boolean {
return this.hasConsentedForDiscovery_ && !!this.pendingProfileProperties_ &&
this.pendingProfileProperties_.length > 0;
}
getSelectedEsimPageNameForTest(): string {
return this.selectedEsimPageName_;
}
}
declare global {
interface HTMLElementTagNameMap {
[EsimFlowUiElement.is]: EsimFlowUiElement;
}
}
customElements.define(EsimFlowUiElement.is, EsimFlowUiElement);