blob: a5c5388fc629fb64bd5c14ab9d7cd11093893362 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview 'settings-about-page' contains version and OS related
* information.
*/
Polymer({
is: 'settings-about-page',
behaviors: [
WebUIListenerBehavior,
settings.MainPageBehavior,
settings.RouteObserverBehavior,
I18nBehavior,
],
properties: {
/** @private {?UpdateStatusChangedEvent} */
currentUpdateStatusEvent_: {
type: Object,
value: {
message: '',
progress: 0,
rollback: false,
status: UpdateStatus.DISABLED
},
},
/**
* Whether the browser/ChromeOS is managed by their organization
* through enterprise policies.
* @private
*/
isManaged_: {
type: Boolean,
value: function() {
return loadTimeData.getBoolean('isManaged');
},
},
// <if expr="chromeos">
/** @private */
hasCheckedForUpdates_: {
type: Boolean,
value: false,
},
/** @private {!BrowserChannel} */
currentChannel_: String,
/** @private {!BrowserChannel} */
targetChannel_: String,
/** @private {?RegulatoryInfo} */
regulatoryInfo_: Object,
/** @private */
hasEndOfLife_: {
type: Boolean,
value: false,
},
/** @private */
hasReleaseNotes_: {
type: Boolean,
value: false,
},
/** @private */
showCrostini: Boolean,
/**
* When the SplitSettings feature is disabled, the about page shows the OS-
* specific parts. When SplitSettings is enabled, the OS-specific parts
* will only show up in chrome://os-settings/help.
* TODO(aee): remove after SplitSettings feature flag is removed.
* @private
*/
showOsSettings_: {
type: Boolean,
value: () => loadTimeData.getBoolean('showOSSettings'),
},
/** @private */
showCrostiniLicense_: {
type: Boolean,
value: false,
},
// </if>
/** @private */
hasInternetConnection_: {
type: Boolean,
value: false,
},
// <if expr="_google_chrome and is_macosx">
/** @private {!PromoteUpdaterStatus} */
promoteUpdaterStatus_: Object,
// </if>
// <if expr="not chromeos">
/** @private {!{obsolete: boolean, endOfLine: boolean}} */
obsoleteSystemInfo_: {
type: Object,
value: function() {
return {
obsolete: loadTimeData.getBoolean('aboutObsoleteNowOrSoon'),
endOfLine: loadTimeData.getBoolean('aboutObsoleteEndOfTheLine'),
};
},
},
// </if>
/** @private */
showUpdateStatus_: {
type: Boolean,
value: false,
},
/** @private */
showButtonContainer_: Boolean,
/** @private */
showRelaunch_: {
type: Boolean,
value: false,
},
// <if expr="chromeos">
/** @private */
showRelaunchAndPowerwash_: {
type: Boolean,
value: false,
computed: 'computeShowRelaunchAndPowerwash_(' +
'currentUpdateStatusEvent_, targetChannel_, currentChannel_)',
},
/** @private */
showCheckUpdates_: {
type: Boolean,
computed: 'computeShowCheckUpdates_(' +
'currentUpdateStatusEvent_, hasCheckedForUpdates_, hasEndOfLife_)',
},
/** @private {!Map<string, string>} */
focusConfig_: {
type: Object,
value: function() {
const map = new Map();
if (settings.routes.DETAILED_BUILD_INFO) {
map.set(
settings.routes.DETAILED_BUILD_INFO.path,
'#detailed-build-info-trigger');
}
return map;
},
},
/** @private */
showUpdateWarningDialog_: {
type: Boolean,
value: false,
},
/** @private */
showTPMFirmwareUpdateLineItem_: {
type: Boolean,
value: false,
},
/** @private */
showTPMFirmwareUpdateDialog_: Boolean,
/** @private {!AboutPageUpdateInfo|undefined} */
updateInfo_: Object,
// </if>
},
observers: [
// <if expr="not chromeos">
'updateShowUpdateStatus_(' +
'obsoleteSystemInfo_, currentUpdateStatusEvent_)',
'updateShowRelaunch_(currentUpdateStatusEvent_)',
'updateShowButtonContainer_(showRelaunch_)',
// </if>
// <if expr="chromeos">
'updateShowUpdateStatus_(' +
'hasEndOfLife_, currentUpdateStatusEvent_,' +
'hasCheckedForUpdates_)',
'updateShowRelaunch_(currentUpdateStatusEvent_, targetChannel_,' +
'currentChannel_)',
'updateShowButtonContainer_(' +
'showRelaunch_, showRelaunchAndPowerwash_, showCheckUpdates_)',
'handleCrostiniEnabledChanged_(prefs.crostini.enabled.value)',
// </if>
],
/** @private {?settings.AboutPageBrowserProxy} */
aboutBrowserProxy_: null,
/** @private {?settings.LifetimeBrowserProxy} */
lifetimeBrowserProxy_: null,
/** @override */
attached: function() {
this.aboutBrowserProxy_ = settings.AboutPageBrowserProxyImpl.getInstance();
this.aboutBrowserProxy_.pageReady();
this.lifetimeBrowserProxy_ =
settings.LifetimeBrowserProxyImpl.getInstance();
// <if expr="chromeos">
if (!this.showOsSettings_) {
return;
}
this.addEventListener('target-channel-changed', e => {
this.targetChannel_ = e.detail;
});
this.aboutBrowserProxy_.getChannelInfo().then(info => {
this.currentChannel_ = info.currentChannel;
this.targetChannel_ = info.targetChannel;
this.startListening_();
});
this.aboutBrowserProxy_.getRegulatoryInfo().then(info => {
this.regulatoryInfo_ = info;
});
this.aboutBrowserProxy_.getEndOfLifeInfo().then(result => {
this.hasEndOfLife_ = !!result.hasEndOfLife;
});
this.aboutBrowserProxy_.getEnabledReleaseNotes().then(result => {
this.hasReleaseNotes_ = result;
});
this.aboutBrowserProxy_.checkInternetConnection().then(result => {
this.hasInternetConnection_ = result;
});
// </if>
// <if expr="not chromeos">
this.startListening_();
// </if>
if (settings.getQueryParameters().get('checkForUpdate') == 'true') {
this.onCheckUpdatesTap_();
}
},
/**
* @param {!settings.Route} newRoute
* @param {settings.Route} oldRoute
*/
currentRouteChanged: function(newRoute, oldRoute) {
settings.MainPageBehavior.currentRouteChanged.call(
this, newRoute, oldRoute);
},
// Override settings.MainPageBehavior method.
containsRoute: function(route) {
return !route || settings.routes.ABOUT.contains(route);
},
/** @private */
startListening_: function() {
this.addWebUIListener(
'update-status-changed', this.onUpdateStatusChanged_.bind(this));
// <if expr="_google_chrome and is_macosx">
this.addWebUIListener(
'promotion-state-changed',
this.onPromoteUpdaterStatusChanged_.bind(this));
// </if>
this.aboutBrowserProxy_.refreshUpdateStatus();
// <if expr="chromeos">
this.addWebUIListener(
'tpm-firmware-update-status-changed',
this.onTPMFirmwareUpdateStatusChanged_.bind(this));
this.aboutBrowserProxy_.refreshTPMFirmwareUpdateStatus();
// </if>
},
/**
* @param {!UpdateStatusChangedEvent} event
* @private
*/
onUpdateStatusChanged_: function(event) {
// <if expr="chromeos">
if (event.status == UpdateStatus.CHECKING) {
this.hasCheckedForUpdates_ = true;
} else if (event.status == UpdateStatus.NEED_PERMISSION_TO_UPDATE) {
this.showUpdateWarningDialog_ = true;
this.updateInfo_ = {version: event.version, size: event.size};
}
// </if>
this.currentUpdateStatusEvent_ = event;
},
// <if expr="_google_chrome and is_macosx">
/**
* @param {!PromoteUpdaterStatus} status
* @private
*/
onPromoteUpdaterStatusChanged_: function(status) {
this.promoteUpdaterStatus_ = status;
},
/**
* If #promoteUpdater isn't disabled, trigger update promotion.
* @private
*/
onPromoteUpdaterTap_: function() {
// This is necessary because #promoteUpdater is not a button, so by default
// disable doesn't do anything.
if (this.promoteUpdaterStatus_.disabled) {
return;
}
this.aboutBrowserProxy_.promoteUpdater();
},
// </if>
/**
* @param {!Event} event
* @private
*/
onLearnMoreTap_: function(event) {
// Stop the propagation of events, so that clicking on links inside
// actionable items won't trigger action.
event.stopPropagation();
},
/** @private */
onReleaseNotesTap_: function() {
this.aboutBrowserProxy_.launchReleaseNotes();
},
/** @private */
onHelpTap_: function() {
this.aboutBrowserProxy_.openHelpPage();
},
/** @private */
onRelaunchTap_: function() {
this.lifetimeBrowserProxy_.relaunch();
},
/** @private */
updateShowUpdateStatus_: function() {
// <if expr="chromeos">
// Do not show the "updated" status if we haven't checked yet or the update
// warning dialog is shown to user.
if (this.currentUpdateStatusEvent_.status == UpdateStatus.UPDATED &&
(!this.hasCheckedForUpdates_ || this.showUpdateWarningDialog_)) {
this.showUpdateStatus_ = false;
return;
}
// Do not show "updated" status if the device is end of life.
if (this.hasEndOfLife_) {
this.showUpdateStatus_ = false;
return;
}
// </if>
// <if expr="not chromeos">
if (this.obsoleteSystemInfo_.endOfLine) {
this.showUpdateStatus_ = false;
return;
}
// </if>
this.showUpdateStatus_ =
this.currentUpdateStatusEvent_.status != UpdateStatus.DISABLED;
},
/**
* Hide the button container if all buttons are hidden, otherwise the
* container displays an unwanted border (see separator class).
* @private
*/
updateShowButtonContainer_: function() {
// <if expr="not chromeos">
this.showButtonContainer_ = this.showRelaunch_;
// </if>
// <if expr="chromeos">
this.showButtonContainer_ = this.showRelaunch_ ||
this.showRelaunchAndPowerwash_ || this.showCheckUpdates_;
// </if>
},
/** @private */
updateShowRelaunch_: function() {
// <if expr="not chromeos">
this.showRelaunch_ = this.checkStatus_(UpdateStatus.NEARLY_UPDATED);
// </if>
// <if expr="chromeos">
this.showRelaunch_ =
this.checkStatus_(UpdateStatus.NEARLY_UPDATED) && !this.isRollback_();
// </if>
},
/**
* @return {boolean}
* @private
*/
shouldShowLearnMoreLink_: function() {
return this.currentUpdateStatusEvent_.status == UpdateStatus.FAILED;
},
/**
* @return {string}
* @private
*/
getUpdateStatusMessage_: function() {
switch (this.currentUpdateStatusEvent_.status) {
case UpdateStatus.CHECKING:
case UpdateStatus.NEED_PERMISSION_TO_UPDATE:
return this.i18nAdvanced('aboutUpgradeCheckStarted');
case UpdateStatus.NEARLY_UPDATED:
// <if expr="chromeos">
if (this.currentChannel_ != this.targetChannel_) {
return this.i18nAdvanced('aboutUpgradeSuccessChannelSwitch');
}
if (this.currentUpdateStatusEvent_.rollback) {
return this.i18nAdvanced('aboutRollbackSuccess');
}
// </if>
return this.i18nAdvanced('aboutUpgradeRelaunch');
case UpdateStatus.UPDATED:
return this.i18nAdvanced('aboutUpgradeUpToDate');
case UpdateStatus.UPDATING:
assert(typeof this.currentUpdateStatusEvent_.progress == 'number');
const progressPercent = this.currentUpdateStatusEvent_.progress + '%';
// <if expr="chromeos">
if (this.currentChannel_ != this.targetChannel_) {
return this.i18nAdvanced('aboutUpgradeUpdatingChannelSwitch', {
substitutions: [
this.i18nAdvanced(
settings.browserChannelToI18nId(this.targetChannel_)),
progressPercent
]
});
}
if (this.currentUpdateStatusEvent_.rollback) {
return this.i18nAdvanced('aboutRollbackInProgress', {
substitutions: [progressPercent],
});
}
// </if>
if (this.currentUpdateStatusEvent_.progress > 0) {
// NOTE(dbeam): some platforms (i.e. Mac) always send 0% while
// updating (they don't support incremental upgrade progress). Though
// it's certainly quite possible to validly end up here with 0% on
// platforms that support incremental progress, nobody really likes
// seeing that they're 0% done with something.
return this.i18nAdvanced('aboutUpgradeUpdatingPercent', {
substitutions: [progressPercent],
});
}
return this.i18nAdvanced('aboutUpgradeUpdating');
default:
function formatMessage(msg) {
return parseHtmlSubset('<b>' + msg + '</b>', ['br', 'pre'])
.firstChild.innerHTML;
}
let result = '';
const message = this.currentUpdateStatusEvent_.message;
if (message) {
result += formatMessage(message);
}
const connectMessage = this.currentUpdateStatusEvent_.connectionTypes;
if (connectMessage) {
result += '<div>' + formatMessage(connectMessage) + '</div>';
}
return result;
}
},
/**
* @return {?string}
* @private
*/
getUpdateStatusIcon_: function() {
// <if expr="chromeos">
// If Chrome OS has reached end of life, display a special icon and
// ignore UpdateStatus.
if (this.hasEndOfLife_) {
return 'os-settings:end-of-life';
}
// </if>
// <if expr="not chromeos">
// If this platform has reached the end of the line, display an error icon
// and ignore UpdateStatus.
if (this.obsoleteSystemInfo_.endOfLine) {
return 'cr:error';
}
// </if>
switch (this.currentUpdateStatusEvent_.status) {
case UpdateStatus.DISABLED_BY_ADMIN:
return 'cr20:domain';
case UpdateStatus.FAILED:
return 'cr:error';
case UpdateStatus.UPDATED:
case UpdateStatus.NEARLY_UPDATED:
return 'settings:check-circle';
default:
return null;
}
},
/**
* @return {?string}
* @private
*/
getThrobberSrcIfUpdating_: function() {
// <if expr="chromeos">
if (this.hasEndOfLife_) {
return null;
}
// </if>
// <if expr="not chromeos">
if (this.obsoleteSystemInfo_.endOfLine) {
return null;
}
// </if>
switch (this.currentUpdateStatusEvent_.status) {
case UpdateStatus.CHECKING:
case UpdateStatus.UPDATING:
return 'chrome://resources/images/throbber_small.svg';
default:
return null;
}
},
/**
* @param {!UpdateStatus} status
* @return {boolean}
* @private
*/
checkStatus_: function(status) {
return this.currentUpdateStatusEvent_.status == status;
},
/** @private */
onManagementPageTap_: function() {
window.location.href = 'chrome://management';
},
// <if expr="chromeos">
/**
* @return {boolean}
* @private
*/
isRollback_: function() {
assert(this.currentChannel_.length > 0);
assert(this.targetChannel_.length > 0);
if (this.currentUpdateStatusEvent_.rollback) {
return true;
}
// Channel switch to a more stable channel is also a rollback
return settings.isTargetChannelMoreStable(
this.currentChannel_, this.targetChannel_);
},
/** @private */
onDetailedBuildInfoTap_: function() {
settings.navigateTo(settings.routes.DETAILED_BUILD_INFO);
},
/** @private */
onRelaunchAndPowerwashTap_: function() {
if (this.currentUpdateStatusEvent_.rollback) {
// Wipe already initiated, simply relaunch.
this.lifetimeBrowserProxy_.relaunch();
} else {
this.lifetimeBrowserProxy_.factoryReset(
/* requestTpmFirmwareUpdate= */ false);
}
},
/**
* @return {boolean}
* @private
*/
computeShowRelaunchAndPowerwash_: function() {
return this.checkStatus_(UpdateStatus.NEARLY_UPDATED) && this.isRollback_();
},
/** @private */
onCheckUpdatesTap_: function() {
this.onUpdateStatusChanged_({status: UpdateStatus.CHECKING});
this.aboutBrowserProxy_.requestUpdate();
},
/**
* @return {boolean}
* @private
*/
computeShowCheckUpdates_: function() {
// Disable update button if the device is end of life.
if (this.hasEndOfLife_) {
return false;
}
// Enable the update button if we are in a stale 'updated' status or
// update has failed. Disable it otherwise.
const staleUpdatedStatus =
!this.hasCheckedForUpdates_ && this.checkStatus_(UpdateStatus.UPDATED);
return staleUpdatedStatus || this.checkStatus_(UpdateStatus.FAILED);
},
/**
* @param {boolean} showCrostiniLicense True if Crostini is enabled and
* Crostini UI is allowed.
* @return {string}
* @private
*/
getAboutProductOsLicense_: function(showCrostiniLicense) {
return showCrostiniLicense ?
this.i18nAdvanced('aboutProductOsWithLinuxLicense') :
this.i18nAdvanced('aboutProductOsLicense');
},
/**
* @param {boolean} enabled True if Crostini is enabled.
* @private
*/
handleCrostiniEnabledChanged_: function(enabled) {
this.showCrostiniLicense_ = enabled && this.showCrostini;
},
/**
* @return {boolean}
* @private
*/
shouldShowSafetyInfo_: function() {
return loadTimeData.getBoolean('shouldShowSafetyInfo');
},
/**
* @return {boolean}
* @private
*/
shouldShowRegulatoryInfo_: function() {
return this.regulatoryInfo_ !== null;
},
/**
* @return {boolean}
* @private
*/
shouldShowRegulatoryOrSafetyInfo_: function() {
return this.showOsSettings_ &&
(this.shouldShowSafetyInfo_() || this.shouldShowRegulatoryInfo_());
},
/** @private */
onUpdateWarningDialogClose_: function() {
this.showUpdateWarningDialog_ = false;
// Shows 'check for updates' button in case that the user cancels the
// dialog and then intends to check for update again.
this.hasCheckedForUpdates_ = false;
},
/**
* @param {!TPMFirmwareUpdateStatusChangedEvent} event
* @private
*/
onTPMFirmwareUpdateStatusChanged_: function(event) {
this.showTPMFirmwareUpdateLineItem_ = event.updateAvailable;
},
/** @private */
onTPMFirmwareUpdateTap_: function() {
this.showTPMFirmwareUpdateDialog_ = true;
},
/** @private */
onPowerwashDialogClose_: function() {
this.showTPMFirmwareUpdateDialog_ = false;
},
// </if>
/** @private */
onProductLogoTap_: function() {
this.$['product-logo'].animate(
{
transform: ['none', 'rotate(-10turn)'],
},
{
duration: 500,
easing: 'cubic-bezier(1, 0, 0, 1)',
});
},
// <if expr="_google_chrome">
/** @private */
onReportIssueTap_: function() {
this.aboutBrowserProxy_.openFeedbackDialog();
},
// </if>
/**
* @return {boolean}
* @private
*/
shouldShowIcons_: function() {
// <if expr="chromeos">
if (this.hasEndOfLife_) {
return true;
}
// </if>
// <if expr="not chromeos">
if (this.obsoleteSystemInfo_.endOfLine) {
return true;
}
// </if>
return this.showUpdateStatus_;
},
});