Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// We use importESModule here instead of static import so that
// the Karma test environment won't choke on this module. This
// is because the Karma test environment already stubs out
// XPCOMUtils, and overrides importESModule to be a no-op (which
// can't be done for a static import statement).
// eslint-disable-next-line mozilla/use-static-import
const { XPCOMUtils } = ChromeUtils.importESModule(
"resource://gre/modules/XPCOMUtils.sys.mjs"
);
import {
actionCreators as ac,
actionTypes as at,
import {
PREF_DEFAULT_VALUE_TOPSTORIES_ENABLED,
PREF_DEFAULT_VALUE_TOPSITES_ENABLED,
// eslint-disable-next-line mozilla/use-static-import
const { AppConstants } = ChromeUtils.importESModule(
"resource://gre/modules/AppConstants.sys.mjs"
);
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
AboutNewTab: "resource:///modules/AboutNewTab.sys.mjs",
NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
Region: "resource://gre/modules/Region.sys.mjs",
SelectableProfileService:
"resource:///modules/profiles/SelectableProfileService.sys.mjs",
});
const ACTIVATION_WINDOW_VARIANT_PREF = "activationWindow.variant";
const ACTIVATION_WINDOW_ENTER_MESSAGE_ID_PREF =
"activationWindow.enterMessageID";
const ACTIVATION_WINDOW_EXIT_MESSAGE_ID_PREF = "activationWindow.exitMessageID";
const TOP_SITES_ENABLED_PREF = "feeds.topsites";
const TOP_STORIES_ENABLED_PREF = "feeds.section.topstories";
const TOP_SITES_USER_VALUE_TEMP_PREF =
"activationWindow.temp.topSitesUserValue";
const TOP_STORIES_USER_VALUE_TEMP_PREF =
"activationWindow.temp.topStoriesUserValue";
const PREF_DEFAULTS = [
{ type: "bool", key: "logowordmark.alwaysVisible", defaultValue: false },
{ type: "bool", key: "feeds.section.topstories", defaultValue: false },
{ type: "bool", key: "discoverystream.enabled", defaultValue: false },
{
type: "bool",
key: "discoverystream.hardcoded-basic-layout",
defaultValue: false,
},
{ type: "string", key: "discoverystream.spocs-endpoint", defaultValue: "" },
{
type: "string",
key: "discoverystream.spocs-endpoint-query",
defaultValue: "",
},
{
type: "string",
key: "discoverystream.sections.personalization.inferred.debug.override",
defaultValue: "",
},
{ type: "string", key: "newNewtabExperience.colors", defaultValue: "" },
];
ChromeUtils.defineLazyGetter(lazy, "logConsole", function () {
return console.createInstance({
prefix: "PrefsFeed",
maxLogLevel: Services.prefs.getBoolPref(
"browser.newtabpage.activity-stream.activationWindow.log",
false
)
? "Debug"
: "Warn",
});
});
export class PrefsFeed {
constructor(prefMap) {
this._prefMap = prefMap;
this._prefs = new Prefs();
this.onExperimentUpdated = this.onExperimentUpdated.bind(this);
this.onTrainhopExperimentUpdated =
this.onTrainhopExperimentUpdated.bind(this);
this.onPocketExperimentUpdated = this.onPocketExperimentUpdated.bind(this);
this.onSmartShortcutsExperimentUpdated =
this.onSmartShortcutsExperimentUpdated.bind(this);
this.onWidgetsUpdated = this.onWidgetsUpdated.bind(this);
this.onOhttpImagesUpdated = this.onOhttpImagesUpdated.bind(this);
this.onInferredPersonalizationExperimentUpdated =
this.onInferredPersonalizationExperimentUpdated.bind(this);
this.onAdsBackendUpdated = this.onAdsBackendUpdated.bind(this);
XPCOMUtils.defineLazyPreferenceGetter(
this,
"inActivationWindowState",
this._prefs._branchStr + ACTIVATION_WINDOW_VARIANT_PREF,
""
);
}
/**
* Handles preference changes by broadcasting them to content processes and
* tracking user changes during the activation window.
*
* @param {string} name - The preference name
* @param {boolean | number | string} value - The new preference value
* @param {boolean} [isUserChange=true] - Whether this change originated from
* a user action (true) or programmatic state transition (false). Only user
* changes are tracked during the activation window.
*/
onPrefChanged(name, value, isUserChange = true) {
const prefItem = this._prefMap.get(name);
if (prefItem) {
let action = "BroadcastToContent";
if (prefItem.skipBroadcast) {
action = "OnlyToMain";
if (prefItem.alsoToPreloaded) {
action = "AlsoToPreloaded";
}
}
this.store.dispatch(
ac[action]({
type: at.PREF_CHANGED,
data: { name, value },
})
);
}
if (isUserChange && this.inActivationWindowState) {
this.trackActivationWindowPrefChange(name, value);
}
}
/**
* Tracks user preference changes during the activation window.
*
* @param {string} name - The preference name
* @param {boolean | number | string} value - The new preference value
*/
trackActivationWindowPrefChange(name, value) {
if (name === TOP_SITES_ENABLED_PREF) {
this._prefs.set(TOP_SITES_USER_VALUE_TEMP_PREF, value);
lazy.logConsole.debug(
`User set top sites to ${value} during activation window`
);
} else if (name === TOP_STORIES_ENABLED_PREF) {
this._prefs.set(TOP_STORIES_USER_VALUE_TEMP_PREF, value);
lazy.logConsole.debug(
`User set top stories to ${value} during activation window`
);
}
}
_setStringPref(values, key, defaultValue) {
this._setPref(values, key, defaultValue, Services.prefs.getStringPref);
}
_setBoolPref(values, key, defaultValue) {
this._setPref(values, key, defaultValue, Services.prefs.getBoolPref);
}
_setIntPref(values, key, defaultValue) {
this._setPref(values, key, defaultValue, Services.prefs.getIntPref);
}
_setPref(values, key, defaultValue, getPrefFunction) {
let value = getPrefFunction(
`browser.newtabpage.activity-stream.${key}`,
defaultValue
);
values[key] = value;
this._prefMap.set(key, { value });
}
/**
* Handler for when experiment data updates.
*/
onExperimentUpdated() {
const value = lazy.NimbusFeatures.newtab.getAllVariables() || {};
this.store.dispatch(
ac.BroadcastToContent({
type: at.PREF_CHANGED,
data: {
name: "featureConfig",
value,
},
})
);
}
/**
* Computes the trainhop config by processing all enrollments.
* Supports two formats:
* - Single payload: { type: "feature", payload: { "enabled": true, ... }}
* - Multi-payload: { type: "multi-payload", payload: [{ type: "feature", payload: { "enabled": true, ... }}] }
* Both formats output the same structure: { "feature": { "enabled": true, ... }}
*/
_getTrainhopConfig() {
const allEnrollments =
lazy.NimbusFeatures.newtabTrainhop.getAllEnrollments() || [];
let enrollmentsToProcess = [];
allEnrollments.forEach(enrollment => {
if (
enrollment?.value?.type === "multi-payload" &&
Array.isArray(enrollment?.value?.payload)
) {
enrollment.value.payload.forEach(item => {
if (item?.type && item?.payload) {
enrollmentsToProcess.push({
value: {
type: item.type,
payload: item.payload,
},
meta: enrollment.meta,
});
}
});
} else if (enrollment?.value?.type) {
enrollmentsToProcess.push(enrollment);
}
});
const valueObj = {};
enrollmentsToProcess.reduce((accumulator, currentValue) => {
if (currentValue?.value?.type) {
if (
!accumulator[currentValue.value.type] ||
(accumulator[currentValue.value.type].meta.isRollout &&
!currentValue.meta.isRollout)
) {
accumulator[currentValue.value.type] = currentValue;
valueObj[currentValue.value.type] = currentValue.value.payload;
}
}
return accumulator;
}, {});
// Bug 2021055: Write weather.display to the default branch so Nimbus sets
// the initial value without overriding an explicit user choice (user branch
// always takes precedence over the default branch).
if (valueObj.widgets?.weatherForecastEnabled && valueObj.weather?.display) {
Services.prefs
.getDefaultBranch(this._prefs._branchStr)
.setStringPref("weather.display", valueObj.weather.display);
}
// Write topSitesRows to the default branch to enable experiments with
// the default row count without overriding an explicit user choice.
if (valueObj.topSites?.topSitesRows) {
Services.prefs
.getDefaultBranch(this._prefs._branchStr)
.setIntPref("topSitesRows", valueObj.topSites.topSitesRows);
}
return valueObj;
}
/**
* Computes the adsBackend features by processing all enrollments.
* This only looks at the flags variable within the adsBackend feature
* and merges each flags object, preferring an experiment over a rollout.
*
*/
_getAdsBackendFeatures() {
/**
* @backward-compat { version 149 }
*
* We can replace `adsBackend?` with `adsBackend` once 149 hits the
* release channel.
*/
const allEnrollments =
lazy.NimbusFeatures.adsBackend?.getAllEnrollments() || [];
const valueObj = {};
allEnrollments.reduce((accumulator, currentValue) => {
if (currentValue?.value?.flags) {
for (const [key, value] of Object.entries(currentValue.value.flags)) {
if (
!accumulator[key] ||
(accumulator[key].meta.isRollout && !currentValue.meta.isRollout)
) {
accumulator[key] = currentValue;
valueObj[key] = value;
}
}
}
return accumulator;
}, {});
return valueObj;
}
/**
* Handler for when experiment data updates.
*/
onTrainhopExperimentUpdated() {
const valueObj = this._getTrainhopConfig();
this.store.dispatch(
ac.BroadcastToContent({
type: at.PREF_CHANGED,
data: {
name: "trainhopConfig",
value: valueObj,
},
})
);
}
/**
* Handler for Pocket specific experiment data updates.
*/
onPocketExperimentUpdated(event, reason) {
const value = lazy.NimbusFeatures.pocketNewtab.getAllVariables() || {};
// Loaded experiments are set up inside init()
if (
reason !== "feature-experiment-loaded" &&
reason !== "feature-rollout-loaded"
) {
this.store.dispatch(
ac.BroadcastToContent({
type: at.PREF_CHANGED,
data: {
name: "pocketConfig",
value,
},
})
);
}
}
/**
* Handler for when smart shortcuts experiment data updates.
*/
onSmartShortcutsExperimentUpdated() {
const value =
lazy.NimbusFeatures.newtabSmartShortcuts.getAllVariables() || {};
this.store.dispatch(
ac.BroadcastToContent({
type: at.PREF_CHANGED,
data: {
name: "smartShortcutsConfig",
value,
},
})
);
}
/**
* Handler for when inferred personalization experiment config values update.
*/
onInferredPersonalizationExperimentUpdated() {
const value =
lazy.NimbusFeatures.newtabInferredPersonalization.getAllVariables() || {};
this.store.dispatch(
ac.BroadcastToContent({
type: at.PREF_CHANGED,
data: {
name: "inferredPersonalizationConfig",
value,
},
})
);
}
/**
* Handler for when widget experiment data updates.
*/
onWidgetsUpdated() {
const value = lazy.NimbusFeatures.newtabWidgets.getAllVariables() || {};
this.store.dispatch(
ac.BroadcastToContent({
type: at.PREF_CHANGED,
data: {
name: "widgetsConfig",
value,
},
})
);
}
/**
* Handler for when OHTTP images experiment data updates.
*/
onOhttpImagesUpdated() {
const value = lazy.NimbusFeatures.newtabOhttpImages.getAllVariables() || {};
this.store.dispatch(
ac.BroadcastToContent({
type: at.PREF_CHANGED,
data: {
name: "ohttpImagesConfig",
value,
},
})
);
}
/**
* Handler for when adsBackend experiment data updates.
*/
onAdsBackendUpdated() {
const valueObj = this._getAdsBackendFeatures();
this.store.dispatch(
ac.BroadcastToContent({
type: at.PREF_CHANGED,
data: {
name: "adsBackendConfig",
value: valueObj,
},
})
);
}
init() {
this._prefs.observeBranch(this);
lazy.NimbusFeatures.newtab.onUpdate(this.onExperimentUpdated);
lazy.NimbusFeatures.newtabTrainhop.onUpdate(
this.onTrainhopExperimentUpdated
);
lazy.NimbusFeatures.pocketNewtab.onUpdate(this.onPocketExperimentUpdated);
lazy.NimbusFeatures.newtabSmartShortcuts.onUpdate(
this.onSmartShortcutsExperimentUpdated
);
lazy.NimbusFeatures.newtabInferredPersonalization.onUpdate(
this.onInferredPersonalizationExperimentUpdated
);
lazy.NimbusFeatures.newtabWidgets.onUpdate(this.onWidgetsUpdated);
lazy.NimbusFeatures.newtabOhttpImages.onUpdate(this.onOhttpImagesUpdated);
/**
* @backward-compat { version 149 }
*
* We can replace `adsBackend?` with `adsBackend` once 149 hits the
* release channel.
*/
lazy.NimbusFeatures.adsBackend?.onUpdate(this.onAdsBackendUpdated);
// Get the initial value of each activity stream pref
const values = {};
for (const name of this._prefMap.keys()) {
values[name] = this._prefs.get(name);
}
// These are not prefs, but are needed to determine stuff in content that can only be
// computed in main process
values.isPrivateBrowsingEnabled = lazy.PrivateBrowsingUtils.enabled;
values.platform = AppConstants.platform;
// Save the geo pref if we have it
if (lazy.Region.home) {
values.region = lazy.Region.home;
this.geo = values.region;
} else if (this.geo !== "") {
// Watch for geo changes and use a dummy value for now
Services.obs.addObserver(this, lazy.Region.REGION_TOPIC);
this.geo = "";
}
// Get the firefox accounts url for links and to send firstrun metrics to.
values.fxa_endpoint = Services.prefs.getStringPref(
"browser.newtabpage.activity-stream.fxaccounts.endpoint",
);
// Get the firefox update channel with values as default, nightly, beta or release
values.appUpdateChannel = Services.prefs.getStringPref(
"app.update.channel",
""
);
// Read the pref for search shortcuts top sites experiment from firefox.js and store it
// in our internal list of prefs to watch
let searchTopSiteExperimentPrefValue = Services.prefs.getBoolPref(
"browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts"
);
values["improvesearch.topSiteSearchShortcuts"] =
searchTopSiteExperimentPrefValue;
this._prefMap.set("improvesearch.topSiteSearchShortcuts", {
value: searchTopSiteExperimentPrefValue,
});
values.mayHaveSponsoredTopSites = Services.prefs.getBoolPref(
"browser.topsites.useRemoteSetting"
);
// Add experiment values and default values
values.featureConfig = lazy.NimbusFeatures.newtab.getAllVariables() || {};
values.pocketConfig =
lazy.NimbusFeatures.pocketNewtab.getAllVariables() || {};
values.smartShortcutsConfig =
lazy.NimbusFeatures.newtabSmartShortcuts.getAllVariables() || {};
values.widgetsConfig =
lazy.NimbusFeatures.newtabWidgets.getAllVariables() || {};
values.trainhopConfig = this._getTrainhopConfig();
values.adsBackendConfig = this._getAdsBackendFeatures();
for (const { type, key, defaultValue } of PREF_DEFAULTS) {
if (type === "bool") {
this._setBoolPref(values, key, defaultValue);
} else if (type === "string") {
this._setStringPref(values, key, defaultValue);
}
}
// Set the initial state of all prefs in redux
this.store.dispatch(
ac.BroadcastToContent({
type: at.PREFS_INITIAL_VALUES,
data: values,
meta: {
isStartup: true,
},
})
);
this.checkForActivationWindow(Temporal.Now.instant(), /* isStartup */ true);
}
uninit() {
this.removeListeners();
}
removeListeners() {
this._prefs.ignoreBranch(this);
lazy.NimbusFeatures.newtab.offUpdate(this.onExperimentUpdated);
lazy.NimbusFeatures.newtabTrainhop.offUpdate(
this.onTrainhopExperimentUpdated
);
lazy.NimbusFeatures.pocketNewtab.offUpdate(this.onPocketExperimentUpdated);
lazy.NimbusFeatures.newtabSmartShortcuts.offUpdate(
this.onSmartShortcutsExperimentUpdated
);
lazy.NimbusFeatures.newtabInferredPersonalization.offUpdate(
this.onInferredPersonalizationExperimentUpdated
);
lazy.NimbusFeatures.newtabWidgets.offUpdate(this.onWidgetsUpdated);
lazy.NimbusFeatures.newtabOhttpImages.offUpdate(this.onOhttpImagesUpdated);
/**
* @backward-compat { version 149 }
*
* We can replace `adsBackend?` with `adsBackend` once 149 hits the
* release channel.
*/
lazy.NimbusFeatures.adsBackend?.offUpdate(this.onAdsBackendUpdated);
if (this.geo === "") {
Services.obs.removeObserver(this, lazy.Region.REGION_TOPIC);
}
}
/**
* Checks whether the current profile is within the activation window and
* updates the activation window state accordingly.
*
* @param {Temporal.Instant} [now=Temporal.Now.instant()] - The current time
* @param {boolean} [isStartup=false] - Whether this is being called during
* browser startup. When true, forces re-application of default branch
* prefs even if already in the activation window state, since default
* branch prefs are not persisted across restarts.
*/
checkForActivationWindow(now = Temporal.Now.instant(), isStartup = false) {
const state = this.store.getState();
if (!state || !state.Prefs) {
return;
}
const { values } = state.Prefs;
const {
enabled = false,
maxProfileAgeInHours = 48,
disableTopSites = false,
disableTopStories = false,
variant = "",
enterActivationWindowMessageID = "",
exitActivationWindowMessageID = "",
} = values?.trainhopConfig?.activationWindowBehavior ?? {};
const { createdInstant } = lazy.AboutNewTab.activityStream;
if (
!enabled ||
!createdInstant ||
!variant ||
lazy.SelectableProfileService.hasCreatedSelectableProfiles()
) {
lazy.logConsole.log("Activation window evaluation skipped.");
lazy.logConsole.debug(
`enabled:${enabled}, createdInstant:${createdInstant}, variant: ${variant}`
);
if (this.inActivationWindowState) {
lazy.logConsole.log(
"Exiting activation window state because evaluation skipped."
);
this.exitActivationWindowState();
}
return;
}
// Are we within the maxProfileAgeInHours period? We compare against the
// current instant and check to see if the creation time is before now,
// but after maxProfileAgeInHours hours ago.
const withinMaxProfileAgeInHours =
Temporal.Instant.compare(createdInstant, now) === -1 &&
Temporal.Instant.compare(
createdInstant,
now.subtract({ hours: maxProfileAgeInHours })
) === 1;
if (withinMaxProfileAgeInHours) {
lazy.logConsole.log(
`Within activation window range (${maxProfileAgeInHours} hours)`
);
this.enterActivationWindowState(
variant,
disableTopSites,
disableTopStories,
enterActivationWindowMessageID,
isStartup
);
} else if (this.inActivationWindowState) {
this.exitActivationWindowState(exitActivationWindowMessageID);
}
}
/**
* Enters the activation window state by setting default branch prefs and
* broadcasting the changes.
*
* @param {string} variant - The activation window variant identifier
* @param {boolean} disableTopSites - Whether to disable top sites by default
* @param {boolean} disableTopStories - Whether to disable top stories by default
* @param {string} enterActivationWindowMessageID - Message ID to display when entering activation window
* @param {boolean} [isStartup=false] - Whether this is being called during
* browser startup. When true, skips the idempotent check to ensure default
* branch prefs are reapplied.
*/
enterActivationWindowState(
variant,
disableTopSites,
disableTopStories,
enterActivationWindowMessageID,
isStartup = false
) {
if (!isStartup && this.inActivationWindowState === variant) {
lazy.logConsole.debug(
`Already in activation window state for variant: ${variant}`
);
return;
}
lazy.logConsole.log("Entering activation window state");
lazy.logConsole.debug(`variant: ${variant}`);
// Clear the variant pref first to ensure we're not in activation window
// state when the preference observer fires (even asynchronously) from the
// default branch changes below.
this._prefs.reset(ACTIVATION_WINDOW_VARIANT_PREF);
const defaultBranch = Services.prefs.getDefaultBranch(
this._prefs._branchStr
);
if (disableTopSites) {
lazy.logConsole.log("Disabling top sites by default.");
defaultBranch.setBoolPref(TOP_SITES_ENABLED_PREF, false);
// This is a programmatic change, not a user action, so don't track it
this.onPrefChanged(
TOP_SITES_ENABLED_PREF,
false,
/* isUserChange */ false
);
}
if (disableTopStories) {
lazy.logConsole.log("Disabling top stories by default.");
defaultBranch.setBoolPref(TOP_STORIES_ENABLED_PREF, false);
// This is a programmatic change, not a user action, so don't track it
this.onPrefChanged(
TOP_STORIES_ENABLED_PREF,
false,
/* isUserChange */ false
);
}
// Set the variant pref last, after default branch changes and broadcasts.
// This prevents the preference observer from incorrectly tracking the
// default branch changes as user actions.
this._prefs.set(ACTIVATION_WINDOW_VARIANT_PREF, variant);
// In the unlikely event that we've exited the activation window in the
// past but somehow re-entered it, clear away the exit message pref so
// that we don't accidentally show any exit messages.
this._prefs.set(ACTIVATION_WINDOW_EXIT_MESSAGE_ID_PREF, "");
// Set the enter message ID pref for ASRouter message targeting
if (enterActivationWindowMessageID) {
this._prefs.set(
ACTIVATION_WINDOW_ENTER_MESSAGE_ID_PREF,
enterActivationWindowMessageID
);
}
lazy.logConsole.log("Activation window enter complete");
}
/**
* Exits the activation window state by resetting default branch prefs and
* restoring any user preference changes made during the window.
*
* @param {string} [exitActivationWindowMessageID=""] - Message ID to display when exiting activation window
*/
exitActivationWindowState(exitActivationWindowMessageID = "") {
lazy.logConsole.log("Exiting activation window state.", new Error().stack);
this._prefs.reset(ACTIVATION_WINDOW_VARIANT_PREF);
// Always reset defaults back to true first
const defaultBranch = Services.prefs.getDefaultBranch(
this._prefs._branchStr
);
lazy.logConsole.debug("Resetting default branch prefs to true");
defaultBranch.setBoolPref(
TOP_SITES_ENABLED_PREF,
PREF_DEFAULT_VALUE_TOPSITES_ENABLED
);
defaultBranch.setBoolPref(
TOP_STORIES_ENABLED_PREF,
PREF_DEFAULT_VALUE_TOPSTORIES_ENABLED
);
// Check temp pref status
const hasTopSitesTempPref = this._prefs.isSet(
TOP_SITES_USER_VALUE_TEMP_PREF
);
const hasTopStoriesTempPref = this._prefs.isSet(
TOP_STORIES_USER_VALUE_TEMP_PREF
);
lazy.logConsole.debug(
`Temp prefs: topSites was disabled=${hasTopSitesTempPref}, topStories was disabled=${hasTopStoriesTempPref}`
);
// Broadcast the default changes (if user hasn't set these prefs, they'll see true)
// If user has set them, setting user values below will trigger another broadcast
if (!hasTopSitesTempPref) {
lazy.logConsole.debug("Broadcasting top sites default change (true)");
// This is a programmatic change, not a user action, so don't track it
this.onPrefChanged(
TOP_SITES_ENABLED_PREF,
true,
/* isUserChange */ false
);
} else {
lazy.logConsole.debug(
"Skipping top sites broadcast - will restore user value"
);
}
if (!hasTopStoriesTempPref) {
lazy.logConsole.debug("Broadcasting top stories default change (true)");
// This is a programmatic change, not a user action, so don't track it
this.onPrefChanged(
TOP_STORIES_ENABLED_PREF,
true,
/* isUserChange */ false
);
} else {
lazy.logConsole.debug(
"Skipping top stories broadcast - will restore user value"
);
}
// Then check if user made changes during activation window and apply them
// Note: _prefs.set() will automatically trigger onPrefChanged() via the observer
if (hasTopSitesTempPref) {
const userValue = this._prefs.get(TOP_SITES_USER_VALUE_TEMP_PREF);
lazy.logConsole.log(
`Restoring user's top sites preference to ${userValue}`
);
this._prefs.set(TOP_SITES_ENABLED_PREF, userValue);
this._prefs.reset(TOP_SITES_USER_VALUE_TEMP_PREF);
lazy.logConsole.debug(
"Top sites user value restored and temp pref cleared"
);
}
if (hasTopStoriesTempPref) {
const userValue = this._prefs.get(TOP_STORIES_USER_VALUE_TEMP_PREF);
lazy.logConsole.log(
`Restoring user's top stories preference to ${userValue}`
);
this._prefs.set(TOP_STORIES_ENABLED_PREF, userValue);
this._prefs.reset(TOP_STORIES_USER_VALUE_TEMP_PREF);
lazy.logConsole.debug(
"Top stories user value restored and temp pref cleared"
);
}
// Clear the enter message ID pref and set exit message ID for ASRouter
this._prefs.set(ACTIVATION_WINDOW_ENTER_MESSAGE_ID_PREF, "");
if (exitActivationWindowMessageID) {
this._prefs.set(
ACTIVATION_WINDOW_EXIT_MESSAGE_ID_PREF,
exitActivationWindowMessageID
);
} else {
this._prefs.set(ACTIVATION_WINDOW_EXIT_MESSAGE_ID_PREF, "");
}
lazy.logConsole.log("Activation window exit complete");
}
observe(subject, topic) {
switch (topic) {
case lazy.Region.REGION_TOPIC:
this.store.dispatch(
ac.BroadcastToContent({
type: at.PREF_CHANGED,
data: { name: "region", value: lazy.Region.home },
})
);
break;
}
}
onAction(action) {
switch (action.type) {
case at.INIT:
this.init();
break;
case at.UNINIT:
this.uninit();
break;
case at.CLEAR_PREF:
Services.prefs.clearUserPref(this._prefs._branchStr + action.data.name);
break;
case at.SET_PREF:
this._prefs.set(action.data.name, action.data.value);
break;
case at.NEW_TAB_STATE_REQUEST: {
this.checkForActivationWindow();
break;
}
}
}
}