mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 04:41:11 +00:00
Bug 1917848 - Show blocklist attention dot and blocklist messagebar message on new hard/soft blocked extensions (AOM/XPIProvider backend changes). r=willdurand
Differential Revision: https://phabricator.services.mozilla.com/D228676
This commit is contained in:
parent
93ced1b5d9
commit
767e1171fd
@ -25,6 +25,8 @@ const MOZ_COMPATIBILITY_NIGHTLY = ![
|
||||
].includes(AppConstants.MOZ_UPDATE_CHANNEL);
|
||||
|
||||
const INTL_LOCALES_CHANGED = "intl:app-locales-changed";
|
||||
const XPIPROVIDER_BLOCKLIST_ATTENTION_UPDATED =
|
||||
"xpi-provider:blocklist-attention-updated";
|
||||
|
||||
const PREF_BLOCKLIST_PINGCOUNTVERSION = "extensions.blocklist.pingCountVersion";
|
||||
const PREF_EM_UPDATE_ENABLED = "extensions.update.enabled";
|
||||
@ -694,6 +696,9 @@ var AddonManagerInternal = {
|
||||
Services.obs.addObserver(this, AMBrowserExtensionsImport.TOPIC_COMPLETE);
|
||||
Services.obs.addObserver(this, AMBrowserExtensionsImport.TOPIC_PENDING);
|
||||
|
||||
// Watch for blocklist attention updates.
|
||||
Services.obs.addObserver(this, XPIPROVIDER_BLOCKLIST_ATTENTION_UPDATED);
|
||||
|
||||
// Ensure all default providers have had a chance to register themselves.
|
||||
const { XPIExports } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/addons/XPIExports.sys.mjs"
|
||||
@ -995,6 +1000,7 @@ var AddonManagerInternal = {
|
||||
);
|
||||
Services.obs.removeObserver(this, AMBrowserExtensionsImport.TOPIC_COMPLETE);
|
||||
Services.obs.removeObserver(this, AMBrowserExtensionsImport.TOPIC_PENDING);
|
||||
Services.obs.removeObserver(this, XPIPROVIDER_BLOCKLIST_ATTENTION_UPDATED);
|
||||
|
||||
AMRemoteSettings.shutdown();
|
||||
|
||||
@ -1065,6 +1071,10 @@ var AddonManagerInternal = {
|
||||
case AMBrowserExtensionsImport.TOPIC_PENDING:
|
||||
this.callManagerListeners("onBrowserExtensionsImportChanged");
|
||||
return;
|
||||
|
||||
case XPIPROVIDER_BLOCKLIST_ATTENTION_UPDATED:
|
||||
this.callManagerListeners("onBlocklistAttentionUpdated");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aData) {
|
||||
@ -3049,6 +3059,30 @@ var AddonManagerInternal = {
|
||||
return this.getAddonsByTypes(null);
|
||||
},
|
||||
|
||||
shouldShowBlocklistAttention() {
|
||||
if (!gStarted) {
|
||||
throw Components.Exception(
|
||||
"AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED
|
||||
);
|
||||
}
|
||||
|
||||
return this._getProviderByName(
|
||||
"XPIProvider"
|
||||
).shouldShowBlocklistAttention();
|
||||
},
|
||||
|
||||
getBlocklistAttentionInfo() {
|
||||
if (!gStarted) {
|
||||
throw Components.Exception(
|
||||
"AddonManager is not initialized",
|
||||
Cr.NS_ERROR_NOT_INITIALIZED
|
||||
);
|
||||
}
|
||||
|
||||
return this._getProviderByName("XPIProvider").getBlocklistAttentionInfo();
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a new AddonManagerListener if the listener is not already registered.
|
||||
*
|
||||
@ -4300,6 +4334,14 @@ export var AddonManager = {
|
||||
return AddonManagerInternal.getAllInstalls();
|
||||
},
|
||||
|
||||
shouldShowBlocklistAttention() {
|
||||
return AddonManagerInternal.shouldShowBlocklistAttention();
|
||||
},
|
||||
|
||||
getBlocklistAttentionInfo() {
|
||||
return AddonManagerInternal.getBlocklistAttentionInfo();
|
||||
},
|
||||
|
||||
isInstallEnabled(aType) {
|
||||
return AddonManagerInternal.isInstallEnabled(aType);
|
||||
},
|
||||
|
@ -1398,6 +1398,22 @@ export var AddonTestUtils = {
|
||||
});
|
||||
},
|
||||
|
||||
promiseManagerEvent(event, checkFn) {
|
||||
return new Promise(resolve => {
|
||||
let listener = {
|
||||
[event](...args) {
|
||||
if (typeof checkFn == "function" && !checkFn(...args)) {
|
||||
return;
|
||||
}
|
||||
AddonManager.removeManagerListener(listener);
|
||||
resolve(args);
|
||||
},
|
||||
};
|
||||
|
||||
AddonManager.addManagerListener(listener);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* A helper method to install AddonInstall and wait for completion.
|
||||
*
|
||||
|
@ -200,6 +200,7 @@ const PROP_JSON_FIELDS = [
|
||||
"requestedPermissions",
|
||||
"icons",
|
||||
"iconURL",
|
||||
"blocklistAttentionDismissed",
|
||||
"blocklistState",
|
||||
"blocklistURL",
|
||||
"startupData",
|
||||
@ -321,7 +322,8 @@ export class AddonInternal {
|
||||
this.appDisabled = false;
|
||||
this.softDisabled = false;
|
||||
this.embedderDisabled = false;
|
||||
this.blocklistState = Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
||||
this.blocklistAttentionDismissed = false;
|
||||
this.blocklistState = nsIBlocklistService.STATE_NOT_BLOCKED;
|
||||
this.blocklistURL = null;
|
||||
this.sourceURI = null;
|
||||
this.releaseNotesURI = null;
|
||||
@ -672,6 +674,15 @@ export class AddonInternal {
|
||||
return app;
|
||||
}
|
||||
|
||||
updateBlocklistAttentionDismissed(val) {
|
||||
if (!this.inDatabase || this.blocklistAttentionDismissed === val) {
|
||||
return;
|
||||
}
|
||||
this.blocklistAttentionDismissed = val;
|
||||
XPIDatabase.maybeUpdateBlocklistAttentionAddonIdsSet(this);
|
||||
XPIDatabase.saveChanges();
|
||||
}
|
||||
|
||||
async findBlocklistEntry() {
|
||||
return lazy.Blocklist.getAddonBlocklistEntry(this.wrapper);
|
||||
}
|
||||
@ -688,6 +699,12 @@ export class AddonInternal {
|
||||
let entry = await this.findBlocklistEntry();
|
||||
let newState = entry ? entry.state : Services.blocklist.STATE_NOT_BLOCKED;
|
||||
|
||||
// Clear the blocklistAttentionDismissed flag if the blocklist state
|
||||
// is changing.
|
||||
if (this.blocklistState !== newState) {
|
||||
this.updateBlocklistAttentionDismissed(false);
|
||||
}
|
||||
|
||||
this.blocklistState = newState;
|
||||
this.blocklistURL = entry && entry.url;
|
||||
|
||||
@ -1266,6 +1283,16 @@ AddonWrapper = class {
|
||||
return null;
|
||||
}
|
||||
|
||||
get blocklistAttentionDismissed() {
|
||||
let addon = addonFor(this);
|
||||
return addon.blocklistAttentionDismissed;
|
||||
}
|
||||
|
||||
set blocklistAttentionDismissed(val) {
|
||||
let addon = addonFor(this);
|
||||
addon.updateBlocklistAttentionDismissed(val);
|
||||
}
|
||||
|
||||
updateBlocklistState(applySoftBlock = true) {
|
||||
return addonFor(this).updateBlocklistState({ applySoftBlock });
|
||||
}
|
||||
@ -1814,6 +1841,13 @@ export const XPIDatabase = {
|
||||
// supported.
|
||||
orphanedAddons: [],
|
||||
|
||||
// Set of the add-on ids for all the add-ons of type extension that are appDisabled or softDisabled
|
||||
// through the blocklist, excluding the ones that the user has already explicitly dismissed before
|
||||
// (used for the blocklist attention dot and messagebar to be shown in the extensions button/panel).
|
||||
//
|
||||
// Set<addonId: string>
|
||||
blocklistAttentionAddonIdsSet: new Set(),
|
||||
|
||||
_saveTask: null,
|
||||
|
||||
// Saved error object if we fail to read an existing database
|
||||
@ -1991,6 +2025,8 @@ export const XPIDatabase = {
|
||||
|
||||
let forEach = this.syncLoadingDB ? arrayForEach : idleForEach;
|
||||
|
||||
this.clearBlocklistAttentionAddonIdsSet();
|
||||
|
||||
// If we got here, we probably have good data
|
||||
// Make AddonInternal instances from the loaded data and save them
|
||||
let addonDB = new Map();
|
||||
@ -2014,6 +2050,7 @@ export const XPIDatabase = {
|
||||
let newAddon = new AddonInternal(loadedAddon);
|
||||
if (loadedAddon.location) {
|
||||
addonDB.set(newAddon._key, newAddon);
|
||||
this.maybeUpdateBlocklistAttentionAddonIdsSet(newAddon);
|
||||
} else {
|
||||
this.orphanedAddons.push(newAddon);
|
||||
}
|
||||
@ -2476,6 +2513,95 @@ export const XPIDatabase = {
|
||||
);
|
||||
},
|
||||
|
||||
shouldShowBlocklistAttention() {
|
||||
return !!this.blocklistAttentionAddonIdsSet.size;
|
||||
},
|
||||
|
||||
shouldShowBlocklistAttentionForAddon(addonInternal) {
|
||||
return (
|
||||
!addonInternal.hidden &&
|
||||
!addonInternal.blocklistAttentionDismissed &&
|
||||
(addonInternal.appDisabled || addonInternal.softDisabled) &&
|
||||
addonInternal.blocklistState > nsIBlocklistService.STATE_NOT_BLOCKED &&
|
||||
// We currently only draw the attention of the users when new add-ons of
|
||||
// type "extension" are being disabled by the blocklist.
|
||||
addonInternal.type === "extension"
|
||||
);
|
||||
},
|
||||
|
||||
clearBlocklistAttentionAddonIdsSet() {
|
||||
this.blocklistAttentionAddonIdsSet.clear();
|
||||
},
|
||||
|
||||
maybeUpdateBlocklistAttentionAddonIdsSet(addonInternal) {
|
||||
const blocklistAttentionSet = this.blocklistAttentionAddonIdsSet;
|
||||
if (!this.shouldShowBlocklistAttentionForAddon(addonInternal)) {
|
||||
blocklistAttentionSet.delete(addonInternal.id);
|
||||
Services.obs.notifyObservers(
|
||||
null,
|
||||
"xpi-provider:blocklist-attention-updated"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
blocklistAttentionSet.add(addonInternal.id);
|
||||
Services.obs.notifyObservers(
|
||||
null,
|
||||
"xpi-provider:blocklist-attention-updated"
|
||||
);
|
||||
},
|
||||
|
||||
removeFromBlocklistAttentionAddonIdsSet(addonInternal) {
|
||||
this.blocklistAttentionAddonIdsSet.delete(addonInternal.id);
|
||||
Services.obs.notifyObservers(
|
||||
null,
|
||||
"xpi-provider:blocklist-attention-updated"
|
||||
);
|
||||
},
|
||||
|
||||
async getBlocklistAttentionInfo() {
|
||||
const attentionAddonIdsSet = this.blocklistAttentionAddonIdsSet;
|
||||
const addonFilter = addonInternal =>
|
||||
attentionAddonIdsSet.has(addonInternal.id) &&
|
||||
this.shouldShowBlocklistAttentionForAddon(addonInternal);
|
||||
let addons = attentionAddonIdsSet.size
|
||||
? await this.getAddonList(addonFilter)
|
||||
: [];
|
||||
// Filter the add-ons list once more synchronously in case any change may have happened
|
||||
// while we were retrieving the add-ons list asynchronously and we may not need to include
|
||||
// some in the blocklist attention message anymore (e.g. because they have been already
|
||||
// dismissed, or changed blocklistState or soft-blocked addon being already re-enabled).
|
||||
addons = addons.filter(addonFilter);
|
||||
|
||||
return {
|
||||
get shouldShow() {
|
||||
return addons.some(addonFilter);
|
||||
},
|
||||
get hasSoftBlocked() {
|
||||
return addons.some(
|
||||
addonInternal =>
|
||||
addonInternal.blocklistState ===
|
||||
nsIBlocklistService.STATE_SOFTBLOCKED
|
||||
);
|
||||
},
|
||||
get hasHardBlocked() {
|
||||
return addons.some(
|
||||
addonInternal =>
|
||||
addonInternal.blocklistState === nsIBlocklistService.STATE_BLOCKED
|
||||
);
|
||||
},
|
||||
get extensionsCount() {
|
||||
return addons.length;
|
||||
},
|
||||
get addons() {
|
||||
return addons.map(addonInternal => addonInternal.wrapper);
|
||||
},
|
||||
dismiss() {
|
||||
addons.forEach(addon => addon.updateBlocklistAttentionDismissed(true));
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Synchronously gets all add-ons in the database.
|
||||
* This is only called from the preference observer for the default
|
||||
@ -2731,6 +2857,7 @@ export const XPIDatabase = {
|
||||
removeAddonMetadata(aAddon) {
|
||||
this.addonDB.delete(aAddon._key);
|
||||
this.saveChanges();
|
||||
this.removeFromBlocklistAttentionAddonIdsSet(aAddon);
|
||||
},
|
||||
|
||||
updateXPIStates(addon) {
|
||||
@ -3009,6 +3136,7 @@ export const XPIDatabase = {
|
||||
}
|
||||
|
||||
this.updateAddonActive(aAddon, !isDisabled);
|
||||
this.maybeUpdateBlocklistAttentionAddonIdsSet(aAddon);
|
||||
|
||||
let bootstrap = XPIExports.XPIInternal.BootstrapScope.get(aAddon);
|
||||
if (isDisabled) {
|
||||
|
@ -119,7 +119,7 @@ const XPI_PERMISSION = "install";
|
||||
|
||||
const XPI_SIGNATURE_CHECK_PERIOD = 24 * 60 * 60;
|
||||
|
||||
const DB_SCHEMA = 36;
|
||||
const DB_SCHEMA = 37;
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
lazy,
|
||||
@ -3275,6 +3275,14 @@ export var XPIProvider = {
|
||||
return { addons: result, fullData: false };
|
||||
},
|
||||
|
||||
shouldShowBlocklistAttention() {
|
||||
return XPIExports.XPIDatabase.shouldShowBlocklistAttention();
|
||||
},
|
||||
|
||||
getBlocklistAttentionInfo() {
|
||||
return XPIExports.XPIDatabase.getBlocklistAttentionInfo();
|
||||
},
|
||||
|
||||
/*
|
||||
* Notified when a preference we're interested in has changed.
|
||||
*
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -15,6 +15,8 @@ run-if = ["os == 'android'"]
|
||||
["test_blocklist_appversion.js"]
|
||||
skip-if = ["os == 'android' && verify"] # times out
|
||||
|
||||
["test_blocklist_attention.js"]
|
||||
|
||||
["test_blocklist_clients.js"]
|
||||
tags = "remote-settings"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user