// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://resources/ash/common/cr_elements/cr_button/cr_button.js';
import 'chrome://resources/ash/common/cr_elements/cr_icon_button/cr_icon_button.js';
import 'chrome://resources/ash/common/cr_elements/cr_toggle/cr_toggle.js';
import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
// <if expr="_google_chrome">
import '/nearby/nearby-share-internal-icons.m.js';
// </if>
import '../common/password_prompt_dialog/password_prompt_dialog.js';
import '../settings_shared.css.js';
import '../nearby_share_page/nearby_share_subpage.js';
import '../os_settings_page/os_settings_animated_pages.js';
import '../os_settings_page/os_settings_subpage.js';
import '../os_settings_page/settings_card.js';
import 'chrome://resources/ash/common/cr_elements/localized_link/localized_link.js';
import './multidevice_feature_toggle.js';
import './multidevice_notification_access_setup_dialog.js';
import './multidevice_permissions_setup_dialog.js';
import './multidevice_subpage.js';
import './multidevice_forget_device_dialog.js';
import {NearbyShareSettingsMixin} from '/shared/nearby_share_settings_mixin.js';
import {PrefsMixin} from '/shared/settings/prefs/prefs_mixin.js';
import {WebUiListenerMixin} from 'chrome://resources/ash/common/cr_elements/web_ui_listener_mixin.js';
import {assert, assertNotReached} from 'chrome://resources/js/assert.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {Visibility} from 'chrome://resources/mojo/chromeos/ash/services/nearby/public/mojom/nearby_share_settings.mojom-webui.js';
import {beforeNextRender, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {assertExhaustive, assertExists} from '../assert_extras.js';
import {DeepLinkingMixin} from '../common/deep_linking_mixin.js';
import {isRevampWayfindingEnabled} from '../common/load_time_booleans.js';
import {RouteOriginMixin} from '../common/route_origin_mixin.js';
import {recordSettingChange} from '../metrics_recorder.js';
import {Section} from '../mojom-webui/routes.mojom-webui.js';
import {Setting} from '../mojom-webui/setting.mojom-webui.js';
import {Route, Router, routes} from '../router.js';
import {MultiDeviceBrowserProxy, MultiDeviceBrowserProxyImpl} from './multidevice_browser_proxy.js';
import {MultiDeviceFeature, MultiDeviceFeatureState, MultiDevicePageContentData, MultiDeviceSettingsMode, PhoneHubFeatureAccessStatus} from './multidevice_constants.js';
import {MultiDeviceFeatureMixin} from './multidevice_feature_mixin.js';
import {getTemplate} from './multidevice_page.html.js';
import TokenInfo = chrome.quickUnlockPrivate.TokenInfo;
function getSettingForMultiDeviceFeature(feature: MultiDeviceFeature): Setting|
null {
switch (feature) {
case MultiDeviceFeature.BETTER_TOGETHER_SUITE:
return Setting.kMultiDeviceOnOff;
case MultiDeviceFeature.PHONE_HUB:
return Setting.kPhoneHubOnOff;
case MultiDeviceFeature.PHONE_HUB_NOTIFICATIONS:
return Setting.kPhoneHubNotificationsOnOff;
case MultiDeviceFeature.PHONE_HUB_TASK_CONTINUATION:
return Setting.kPhoneHubTaskContinuationOnOff;
case MultiDeviceFeature.PHONE_HUB_CAMERA_ROLL:
return Setting.kPhoneHubCameraRollOnOff;
case MultiDeviceFeature.SMART_LOCK:
return Setting.kSmartLockOnOff;
case MultiDeviceFeature.WIFI_SYNC:
return Setting.kWifiSyncOnOff;
case MultiDeviceFeature.ECHE:
return Setting.kPhoneHubAppsOnOff;
case MultiDeviceFeature.INSTANT_TETHERING:
return Setting.kInstantTetheringOnOff;
default:
assertExhaustive(feature);
}
}
const SettingsMultidevicePageElementBase =
NearbyShareSettingsMixin(MultiDeviceFeatureMixin(RouteOriginMixin(
DeepLinkingMixin(PrefsMixin(WebUiListenerMixin(PolymerElement))))));
export class SettingsMultidevicePageElement extends
SettingsMultidevicePageElementBase {
static get is() {
return 'settings-multidevice-page' as const;
}
static get template() {
return getTemplate();
}
static get properties() {
return {
section_: {
type: Number,
value: Section.kMultiDevice,
readOnly: true,
},
/**
* Authentication token provided by password-prompt-dialog.
*/
authToken_: {
type: Object,
},
/**
* Feature which the user has requested to be enabled but could not be
* enabled immediately because authentication (i.e., entering a password)
* is required. This value is initialized to null, is set when the
* password dialog is opened, and is reset to null again once the password
* dialog is closed.
*/
featureToBeEnabledOnceAuthenticated_: {
type: Number,
value: null,
},
showPasswordPromptDialog_: {
type: Boolean,
value: false,
},
showPhonePermissionSetupDialog_: {
type: Boolean,
value: false,
},
/**
* Whether or not Nearby Share is supported which controls if the Nearby
* Share settings and subpage are accessible.
*/
isNearbyShareSupported_: {
type: Boolean,
value: function() {
return loadTimeData.getBoolean('isNearbyShareSupported');
},
},
shouldEnableNearbyShareBackgroundScanningRevamp_: {
type: Boolean,
computed: `computeShouldEnableNearbyShareBackgroundScanningRevamp_(
settings.isFastInitiationHardwareSupported)`,
},
isSettingsRetreived: {
type: Boolean,
value: false,
},
/**
* Used by DeepLinkingMixin to focus this page's deep links.
*/
supportedSettingIds: {
type: Object,
value: () => new Set<Setting>([
Setting.kSetUpMultiDevice,
Setting.kVerifyMultiDeviceSetup,
Setting.kMultiDeviceOnOff,
Setting.kNearbyShareDeviceVisibility,
Setting.kNearbyShareOnOff,
]),
},
/**
* Reflects the password sub-dialog property.
*/
isPasswordDialogShowing_: {
type: Boolean,
value: false,
},
/**
* Reflects the pin number sub-dialog property.
*/
isPinNumberDialogShowing_: {
type: Boolean,
value: false,
},
isChromeosScreenLockEnabled_: {
type: Boolean,
value: function() {
return loadTimeData.getBoolean('isChromeosScreenLockEnabled');
},
},
isPhoneScreenLockEnabled_: {
type: Boolean,
value: function() {
return loadTimeData.getBoolean('isPhoneScreenLockEnabled');
},
},
isRevampWayfindingEnabled_: {
type: Boolean,
value: () => {
return isRevampWayfindingEnabled();
},
},
isNameEnabled_: {
type: Boolean,
value: () => {
return loadTimeData.getBoolean('isNameEnabled');
},
},
shouldShowForgetDeviceDialog_: {
type: Boolean,
value: false,
},
isQuickShareV2Enabled_: {
type: Boolean,
value: () => loadTimeData.getBoolean('isQuickShareV2Enabled'),
},
};
}
isSettingsRetreived: boolean;
private authToken_: TokenInfo|undefined;
private browserProxy_: MultiDeviceBrowserProxy;
private featureToBeEnabledOnceAuthenticated_: MultiDeviceFeature|null;
private isChromeosScreenLockEnabled_: boolean;
private isNearbyShareSupported_: boolean;
private isPasswordDialogShowing_: boolean;
private isPhoneScreenLockEnabled_: boolean;
private isPinNumberDialogShowing_: boolean;
private isQuickShareV2Enabled_: boolean;
private isRevampWayfindingEnabled_: boolean;
private section_: Section;
private shouldEnableNearbyShareBackgroundScanningRevamp_: boolean;
private showPasswordPromptDialog_: boolean;
private shouldShowForgetDeviceDialog_: boolean;
private showPhonePermissionSetupDialog_: boolean;
constructor() {
super();
/** RouteOriginMixin override */
this.route = routes.MULTIDEVICE;
this.browserProxy_ = MultiDeviceBrowserProxyImpl.getInstance();
}
override ready(): void {
super.ready();
this.addEventListener('close', this.onDialogClose_);
this.addEventListener('feature-toggle-clicked', (event) => {
this.onFeatureToggleClicked_(event);
});
this.addEventListener(
'forget-device-requested', this.onForgetDeviceRequested_);
this.addEventListener(
'permission-setup-requested', this.onPermissionSetupRequested_);
this.addWebUiListener(
'settings.updateMultidevicePageContentData',
this.onPageContentDataChanged_.bind(this));
this.addWebUiListener(
'settings.OnEnableScreenLockChanged',
this.onEnableScreenLockChanged_.bind(this));
this.addWebUiListener(
'settings.OnScreenLockStatusChanged',
this.onScreenLockStatusChanged_.bind(this));
this.addFocusConfig(
routes.MULTIDEVICE_FEATURES, '#multideviceItem .subpage-arrow');
this.browserProxy_.getPageContentData().then(
(data) => this.onInitialPageContentDataFetched_(data));
}
/**
* Overridden from NearbyShareSettingsMixin.
*/
override onSettingsRetrieved(): void {
this.isSettingsRetreived = true;
}
/**
* RouteObserverMixin override
*/
override currentRouteChanged(newRoute: Route, oldRoute?: Route): void {
super.currentRouteChanged(newRoute, oldRoute);
this.leaveNestedPageIfNoHostIsSet_();
// Does not apply to this page.
if (newRoute !== this.route) {
return;
}
this.attemptDeepLink();
}
private getLabelText_(): string {
if (this.isRevampWayfindingEnabled_) {
return this.i18n('multideviceSetupItemHeading');
}
return this.pageContentData.hostDeviceName ||
this.i18n('multideviceSetupItemHeading');
}
private getSubLabelInnerHtml_(): TrustedHTML|string {
if (!this.isSuiteAllowedByPolicy()) {
return this.i18nAdvanced('multideviceSetupSummary');
}
switch (this.pageContentData.mode) {
case MultiDeviceSettingsMode.NO_ELIGIBLE_HOSTS:
return this.i18nAdvanced('multideviceNoHostText');
case MultiDeviceSettingsMode.NO_HOST_SET:
return this.i18nAdvanced('multideviceSetupSummary');
case MultiDeviceSettingsMode.HOST_SET_WAITING_FOR_SERVER:
// Intentional fall-through.
case MultiDeviceSettingsMode.HOST_SET_WAITING_FOR_VERIFICATION:
return this.i18nAdvanced('multideviceVerificationText');
case MultiDeviceSettingsMode.HOST_SET_VERIFIED:
if (this.isRevampWayfindingEnabled_) {
assertExists(this.pageContentData.hostDeviceName);
return this.pageContentData.hostDeviceName;
}
return this.isSuiteOn() ? this.i18n('multideviceEnabled') :
this.i18n('multideviceDisabled');
default:
assertNotReached();
}
}
private getButtonText_(): string {
switch (this.pageContentData.mode) {
case MultiDeviceSettingsMode.NO_HOST_SET:
return this.i18n('multideviceSetupButton');
case MultiDeviceSettingsMode.HOST_SET_WAITING_FOR_SERVER:
// Intentional fall-through.
case MultiDeviceSettingsMode.HOST_SET_WAITING_FOR_VERIFICATION:
return this.i18n('multideviceVerifyButton');
default:
return '';
}
}
private getButtonA11yLabel_(): string {
switch (this.pageContentData.mode) {
case MultiDeviceSettingsMode.NO_HOST_SET:
return this.i18n('multideviceSetupButtonA11yLabel');
case MultiDeviceSettingsMode.HOST_SET_WAITING_FOR_SERVER:
// Intentional fall-through.
case MultiDeviceSettingsMode.HOST_SET_WAITING_FOR_VERIFICATION:
return this.i18n('multideviceVerifyButtonA11yLabel');
default:
return '';
}
}
private getTextAriaHidden_(): string {
// When host is set and verified, we only show subpage arrow button and
// toggle. In this case, we avoid the navigation stops on the text to make
// navigating easier. The arrow button is labeled and described by the text,
// so the text is still available to assistive tools.
return String(
this.pageContentData.mode ===
MultiDeviceSettingsMode.HOST_SET_VERIFIED);
}
private shouldShowButton_(): boolean {
return [
MultiDeviceSettingsMode.NO_HOST_SET,
MultiDeviceSettingsMode.HOST_SET_WAITING_FOR_SERVER,
MultiDeviceSettingsMode.HOST_SET_WAITING_FOR_VERIFICATION,
].includes(this.pageContentData.mode);
}
private shouldShowToggle_(): boolean {
return this.pageContentData.mode ===
MultiDeviceSettingsMode.HOST_SET_VERIFIED;
}
/**
* Whether to show the separator bar and, if the state calls for a chevron
* (a.k.a. subpage arrow) routing to the subpage, the chevron.
*/
private shouldShowSeparatorAndSubpageArrow_(): boolean {
return this.pageContentData.mode !==
MultiDeviceSettingsMode.NO_ELIGIBLE_HOSTS;
}
private doesClickOpenSubpage_(): boolean {
return this.isHostSet();
}
private handleItemClick_(event: Event): void {
// We do not open the subpage if the click was on a link.
if ((event.composedPath()[0] as HTMLElement).tagName === 'A') {
event.stopPropagation();
return;
}
if (!this.isHostSet()) {
return;
}
Router.getInstance().navigateTo(routes.MULTIDEVICE_FEATURES);
}
private handleButtonClick_(event: Event): void {
event.stopPropagation();
switch (this.pageContentData.mode) {
case MultiDeviceSettingsMode.NO_HOST_SET:
this.browserProxy_.showMultiDeviceSetupDialog();
return;
case MultiDeviceSettingsMode.HOST_SET_WAITING_FOR_SERVER:
// Intentional fall-through.
case MultiDeviceSettingsMode.HOST_SET_WAITING_FOR_VERIFICATION:
// If this device is waiting for action on the server or the host
// device, clicking the button should trigger this action.
this.browserProxy_.retryPendingHostSetup();
}
}
private openPasswordPromptDialog_(): void {
this.showPasswordPromptDialog_ = true;
}
private onDialogClose_(event: Event): void {
event.stopPropagation();
if (event.composedPath().some(
element =>
(element as HTMLElement).id === 'multidevicePasswordPrompt')) {
this.onPasswordPromptDialogClose_();
}
}
private onPasswordPromptDialogClose_(): void {
// The password prompt should only be shown when there is a feature waiting
// to be enabled.
assert(this.featureToBeEnabledOnceAuthenticated_ !== null);
// If |this.authToken_| is set when the dialog has been closed, this means
// that the user entered the correct password into the dialog. Thus, send
// all pending features to be enabled.
if (this.authToken_) {
this.browserProxy_.setFeatureEnabledState(
this.featureToBeEnabledOnceAuthenticated_, true /* enabled */,
this.authToken_.token);
recordSettingChange(Setting.kMultiDeviceOnOff);
// Reset |this.authToken_| now that it has been used. This ensures that
// users cannot keep an old auth token and reuse it on an subsequent
// request.
this.authToken_ = undefined;
}
// Either the feature was enabled above or the user canceled the request by
// clicking "Cancel" on the password dialog. Thus, there is no longer a need
// to track any pending feature.
this.featureToBeEnabledOnceAuthenticated_ = null;
// Remove the password prompt dialog from the DOM.
this.showPasswordPromptDialog_ = false;
}
/**
* Attempt to enable the provided feature. If not authenticated (i.e.,
* |authToken_| is invalid), display the password prompt to begin the
* authentication process.
*/
private onFeatureToggleClicked_(
event: CustomEvent<{feature: MultiDeviceFeature, enabled: boolean}>):
void {
const feature = event.detail.feature;
const enabled = event.detail.enabled;
// If the feature required authentication to be enabled, open the password
// prompt dialog. This is required every time the user enables a security-
// sensitive feature (i.e., use of stale auth tokens is not acceptable).
if (enabled && this.isAuthenticationRequiredToEnable_(feature)) {
this.featureToBeEnabledOnceAuthenticated_ = feature;
this.openPasswordPromptDialog_();
return;
}
// If the feature to enable is Phone Hub Notifications, notification access
// must have been granted before the feature can be enabled.
if (feature === MultiDeviceFeature.PHONE_HUB_NOTIFICATIONS && enabled) {
switch (this.pageContentData.notificationAccessStatus) {
case PhoneHubFeatureAccessStatus.PROHIBITED:
assertNotReached('Cannot enable notification access; prohibited');
case PhoneHubFeatureAccessStatus.AVAILABLE_BUT_NOT_GRANTED:
this.showPhonePermissionSetupDialog_ = true;
return;
default:
// Fall through and attempt to toggle feature.
break;
}
}
// Disabling any feature does not require authentication, and enable some
// features does not require authentication.
this.browserProxy_.setFeatureEnabledState(feature, enabled);
const changedSettingId = getSettingForMultiDeviceFeature(feature);
if (changedSettingId !== null) {
recordSettingChange(changedSettingId, {boolValue: enabled});
}
}
private isAuthenticationRequiredToEnable_(feature: MultiDeviceFeature):
boolean {
// Enabling SmartLock always requires authentication.
if (feature === MultiDeviceFeature.SMART_LOCK) {
return true;
}
// Enabling any feature besides SmartLock and the Better Together suite does
// not require authentication.
if (feature !== MultiDeviceFeature.BETTER_TOGETHER_SUITE) {
return false;
}
const smartLockState = this.getFeatureState(MultiDeviceFeature.SMART_LOCK);
// If the user is enabling the Better Together suite and this change would
// result in SmartLock being implicitly enabled, authentication is required.
// SmartLock is implicitly enabled if it is only currently not enabled due
// to the suite being disabled or due to the SmartLock host device not
// having a lock screen set.
return smartLockState ===
MultiDeviceFeatureState.UNAVAILABLE_SUITE_DISABLED ||
smartLockState ===
MultiDeviceFeatureState.UNAVAILABLE_INSUFFICIENT_SECURITY;
}
private onForgetDeviceRequested_(): void {
this.browserProxy_.removeHostDevice();
recordSettingChange(Setting.kForgetPhone);
Router.getInstance().navigateTo(routes.MULTIDEVICE);
}
private onPermissionSetupRequested_(): void {
this.showPhonePermissionSetupDialog_ = true;
}
/**
* Checks if the user is in a nested page without a host set and, if so,
* navigates them back to the main page.
*/
private leaveNestedPageIfNoHostIsSet_(): void {
// Wait for data to arrive.
if (!this.pageContentData) {
return;
}
// Host status doesn't matter if we are navigating to Nearby Share
// settings.
if (routes.NEARBY_SHARE === Router.getInstance().currentRoute) {
return;
}
// If the user gets to the a nested page without a host (e.g. by clicking a
// stale 'existing user' notifications after forgetting their host) we
// direct them back to the main settings page.
if (routes.MULTIDEVICE !== Router.getInstance().currentRoute &&
routes.MULTIDEVICE.contains(Router.getInstance().currentRoute) &&
!this.isHostSet()) {
// Render MULTIDEVICE page before the MULTIDEVICE_FEATURES has a chance.
beforeNextRender(this, () => {
Router.getInstance().navigateTo(routes.MULTIDEVICE);
});
}
}
private onInitialPageContentDataFetched_(newData: MultiDevicePageContentData):
void {
this.onPageContentDataChanged_(newData);
// Show the notification access dialog if the url contains the correct
// param.
// Show combined access dialog with URL having param and features.
const urlParams = Router.getInstance().getQueryParameters();
if (urlParams.get('showPhonePermissionSetupDialog') !== null) {
this.showPhonePermissionSetupDialog_ = true;
Router.getInstance().navigateTo(routes.MULTIDEVICE_FEATURES);
}
}
private onPageContentDataChanged_(newData: MultiDevicePageContentData): void {
this.pageContentData = newData;
this.leaveNestedPageIfNoHostIsSet_();
}
private onTokenObtained_(e: CustomEvent<TokenInfo>): void {
this.authToken_ = e.detail;
}
private isNearbyShareDisallowedByPolicy_(): boolean {
if (!this.pageContentData) {
return false;
}
return this.pageContentData.isNearbyShareDisallowedByPolicy;
}
private getNearbyShareDescription_(visibility: Visibility|undefined): string
|undefined {
if (visibility === undefined) {
return this.i18n('nearbyShareDescriptionHidden');
}
switch (visibility) {
case Visibility.kAllContacts:
return this.i18n('nearbyShareDescriptionVisibleToAllContacts');
case Visibility.kSelectedContacts:
return this.i18n('nearbyShareDescriptionVisibleToSelectedContacts');
case Visibility.kYourDevices:
return this.i18n('nearbyShareDescriptionVisibleToYourDevices');
case Visibility.kNoOne:
case Visibility.kUnknown:
return this.i18n('nearbyShareDescriptionHidden');
default:
assertNotReached();
}
}
private showNearbyShareToggle_(isOnboardingComplete: boolean): boolean {
return !this.isQuickShareV2Enabled_ &&
(isOnboardingComplete || this.isNearbyShareDisallowedByPolicy_());
}
private showNearbyShareSetupButton_(isOnboardingComplete: boolean): boolean {
return !isOnboardingComplete && !this.isNearbyShareDisallowedByPolicy_();
}
private showNearbyShareOnOffString_(isOnboardingComplete: boolean): boolean {
return !this.isQuickShareV2Enabled_ &&
(isOnboardingComplete && !this.isNearbyShareDisallowedByPolicy_());
}
private showNearbyShareSetUpDescription_(isOnboardingComplete: boolean):
boolean {
return !isOnboardingComplete || this.isNearbyShareDisallowedByPolicy_();
}
private nearbyShareClick_(): void {
if (this.isNearbyShareDisallowedByPolicy_()) {
return;
}
const nearbyEnabled = this.getPref('nearby_sharing.enabled').value;
const onboardingComplete =
this.getPref('nearby_sharing.onboarding_complete').value;
// If background scanning is enabled the subpage is accessible regardless of
// whether Nearby Share is on or off so that users can enable/disable the
// "Nearby device is trying to share" notification.
if (this.shouldEnableNearbyShareBackgroundScanningRevamp_) {
Router.getInstance().navigateTo(routes.NEARBY_SHARE);
return;
}
let params = undefined;
if (!nearbyEnabled) {
if (onboardingComplete) {
// If we have already run onboarding at least once, we don't need to do
// it again, just enabled the feature in place.
this.setPrefValue('nearby_sharing.enabled', true);
return;
}
// Otherwise we need to go into the subpage and trigger the onboarding
// dialog.
params = new URLSearchParams();
// Set by metrics to determine entrypoint for onboarding
params.set('entrypoint', 'settings');
params.set('onboarding', '');
}
Router.getInstance().navigateTo(routes.NEARBY_SHARE, params);
}
private showPermissionsSetupDialog_(): boolean {
if (!this.showPhonePermissionSetupDialog_) {
return false;
}
return !this.pageContentData.isPhoneHubPermissionsDialogSupported;
}
private showNewPermissionsSetupDialog_(): boolean {
if (!this.showPhonePermissionSetupDialog_) {
return false;
}
return this.pageContentData.isPhoneHubPermissionsDialogSupported;
}
private onHidePhonePermissionsSetupDialog_(): void {
// Don't close the main dialog if the pin number sub-dialog is open.
if (this.isPinNumberDialogShowing_) {
this.isPinNumberDialogShowing_ = false;
return;
}
// Don't close the main dialog if the password sub-dialog is open.
if (this.isPasswordDialogShowing_) {
this.isPasswordDialogShowing_ = false;
return;
}
this.showPhonePermissionSetupDialog_ = false;
// By default, dialog.close() returns the focus to the previously focused
// element if the element is still focusable and within the viewport,
// otherwise move the focus to <body>. Therefore, we need to move focus
// manually to the subpage.
this.shadowRoot!.getElementById(
'settingsMultideviceSubpageWrapper')!.focus();
}
private onPinNumberSelected_(e: CustomEvent<{isPinNumberSelected: boolean}>):
void {
assert(typeof e.detail.isPinNumberSelected === 'boolean');
this.isPinNumberDialogShowing_ = e.detail.isPinNumberSelected;
}
private handleNearbySetUpClick_(): void {
const params = new URLSearchParams();
params.set('onboarding', '');
// Set by metrics to determine entrypoint for onboarding
params.set('entrypoint', 'settings');
Router.getInstance().navigateTo(routes.NEARBY_SHARE, params);
}
private shouldShowNearbyShareSubpageArrow_(
isNearbySharingEnabled: boolean,
shouldEnableNearbyShareBackgroundScanningRevamp: boolean): boolean {
// If the background scanning feature is enabled but Nearby Sharing is
// disabled the subpage should be accessible. The subpage is also accessible
// pre-onboarding.
return (shouldEnableNearbyShareBackgroundScanningRevamp ||
isNearbySharingEnabled) &&
!this.isNearbyShareDisallowedByPolicy_();
}
private computeShouldEnableNearbyShareBackgroundScanningRevamp_(
isHardwareSupported: boolean): boolean {
return isHardwareSupported;
}
/**
* Whether the combined setup for Notifications and Camera Roll is supported
* on the connected phone.
*/
private isCombinedSetupSupported_(): boolean {
return this.pageContentData.isPhoneHubFeatureCombinedSetupSupported;
}
/**
* Due to loadTimeData is not guaranteed to be consistent between page
* refreshes, use FireWebUIListener() to update dynamic value of screen lock
* setting.
*/
private onEnableScreenLockChanged_(enabled: boolean): void {
this.isChromeosScreenLockEnabled_ = enabled;
}
/**
* Due to loadTimeData is not guaranteed to be consistent between page
* refreshes, use FireWebUIListener() to update dynamic value of screen lock
* status of phone.
*/
private onScreenLockStatusChanged_(enabled: boolean): void {
this.isPhoneScreenLockEnabled_ = enabled;
}
private getMultideviceSubpageTitle_(): string {
if (this.isRevampWayfindingEnabled_) {
const deviceName = this.pageContentData.hostDeviceName || '';
return this.i18n('multideviceSubpageTitle', deviceName);
}
return this.pageContentData.hostDeviceName ||
this.i18n('multideviceSetupItemHeading');
}
private showForgetDeviceDialog_(): void {
this.shouldShowForgetDeviceDialog_ = true;
}
private closeForgetDeviceDialog_(): void {
this.shouldShowForgetDeviceDialog_ = false;
}
}
declare global {
interface HTMLElementTagNameMap {
[SettingsMultidevicePageElement.is]: SettingsMultidevicePageElement;
}
}
customElements.define(
SettingsMultidevicePageElement.is, SettingsMultidevicePageElement);