зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1618314 - Remove import suggestions on user opt-out or automatically r=MattN
Allow 3 showing of import suggestions debouncing multiple impressions within 10 seconds. Also treat deleting a suggestion as opt-out. Differential Revision: https://phabricator.services.mozilla.com/D87805
This commit is contained in:
Родитель
6d2844352a
Коммит
a193e2372f
|
@ -1852,6 +1852,7 @@ pref("signon.management.page.showPasswordSyncNotification", true);
|
|||
pref("signon.passwordEditCapture.enabled", true);
|
||||
pref("signon.showAutoCompleteFooter", true);
|
||||
pref("signon.showAutoCompleteImport", "import");
|
||||
pref("signon.suggestImportCount", 3);
|
||||
|
||||
// Enable the "Simplify Page" feature in Print Preview. This feature
|
||||
// is disabled by default in toolkit.
|
||||
|
|
|
@ -240,14 +240,26 @@ class ImportableLearnMoreAutocompleteItem extends AutocompleteItem {
|
|||
}
|
||||
|
||||
class ImportableLoginsAutocompleteItem extends AutocompleteItem {
|
||||
constructor(browserId, hostname) {
|
||||
constructor(browserId, hostname, actor) {
|
||||
super("importableLogins");
|
||||
this.label = browserId;
|
||||
this.comment = hostname;
|
||||
this._actor = actor;
|
||||
|
||||
// This is sent for every item (re)shown, but the parent will debounce to
|
||||
// reduce the count by 1 total.
|
||||
this._actor.sendAsyncMessage(
|
||||
"PasswordManager:decreaseSuggestImportCount",
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
removeFromStorage() {
|
||||
Services.telemetry.recordEvent("exp_import", "event", "delete", this.label);
|
||||
this._actor.sendAsyncMessage(
|
||||
"PasswordManager:decreaseSuggestImportCount",
|
||||
100
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -364,7 +376,8 @@ function LoginAutoCompleteResult(
|
|||
if (!logins.length && importableBrowsers) {
|
||||
this._rows.push(
|
||||
...importableBrowsers.map(
|
||||
browserId => new ImportableLoginsAutocompleteItem(browserId, hostname)
|
||||
browserId =>
|
||||
new ImportableLoginsAutocompleteItem(browserId, hostname, actor)
|
||||
)
|
||||
);
|
||||
this._rows.push(new ImportableLearnMoreAutocompleteItem());
|
||||
|
|
|
@ -111,6 +111,11 @@ this.LoginHelper = {
|
|||
"signon.storeWhenAutocompleteOff"
|
||||
);
|
||||
|
||||
this.suggestImportCount = Services.prefs.getIntPref(
|
||||
"signon.suggestImportCount",
|
||||
0
|
||||
);
|
||||
|
||||
if (
|
||||
Services.prefs.getBoolPref(
|
||||
"signon.testOnlyUserHasInteractedByPrefValue",
|
||||
|
|
|
@ -127,7 +127,8 @@ Services.ppmm.addMessageListener("PasswordManager:findRecipes", message => {
|
|||
async function getImportableLogins(formOrigin) {
|
||||
// Include the experiment state for data and UI decisions; otherwise skip
|
||||
// importing if not supported or disabled.
|
||||
const state = LoginHelper.showAutoCompleteImport;
|
||||
const state =
|
||||
LoginHelper.suggestImportCount > 0 && LoginHelper.showAutoCompleteImport;
|
||||
return state
|
||||
? {
|
||||
browsers: await ChromeMigrationUtils.getImportableLogins(formOrigin),
|
||||
|
@ -256,6 +257,11 @@ class LoginManagerParent extends JSWindowActorParent {
|
|||
break;
|
||||
}
|
||||
|
||||
case "PasswordManager:decreaseSuggestImportCount": {
|
||||
this.decreaseSuggestImportCount(data);
|
||||
break;
|
||||
}
|
||||
|
||||
case "PasswordManager:findLogins": {
|
||||
return this.sendLoginDataToChild(
|
||||
context.origin,
|
||||
|
@ -347,6 +353,36 @@ class LoginManagerParent extends JSWindowActorParent {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the remaining number of import suggestion impressions with debounce
|
||||
* to allow multiple popups showing the "same" items to count as one.
|
||||
*/
|
||||
decreaseSuggestImportCount(count) {
|
||||
// Delay an existing timer with a potentially larger count.
|
||||
if (this._suggestImportTimer) {
|
||||
this._suggestImportTimer.delay =
|
||||
LoginManagerParent.SUGGEST_IMPORT_DEBOUNCE_MS;
|
||||
this._suggestImportCount = Math.max(count, this._suggestImportCount);
|
||||
return;
|
||||
}
|
||||
|
||||
this._suggestImportTimer = Cc["@mozilla.org/timer;1"].createInstance(
|
||||
Ci.nsITimer
|
||||
);
|
||||
this._suggestImportTimer.init(
|
||||
() => {
|
||||
this._suggestImportTimer = null;
|
||||
Services.prefs.setIntPref(
|
||||
"signon.suggestImportCount",
|
||||
LoginHelper.suggestImportCount - this._suggestImportCount
|
||||
);
|
||||
},
|
||||
LoginManagerParent.SUGGEST_IMPORT_DEBOUNCE_MS,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT
|
||||
);
|
||||
this._suggestImportCount = count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger a login form fill and send relevant data (e.g. logins and recipes)
|
||||
* to the child process (LoginManagerChild).
|
||||
|
@ -1317,6 +1353,8 @@ class LoginManagerParent extends JSWindowActorParent {
|
|||
}
|
||||
}
|
||||
|
||||
LoginManagerParent.SUGGEST_IMPORT_DEBOUNCE_MS = 10000;
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
LoginManagerParent,
|
||||
"_repromptTimeout",
|
||||
|
|
|
@ -20,9 +20,26 @@ add_task(async function check_fluent_ids() {
|
|||
}
|
||||
});
|
||||
|
||||
add_task(async function import_suggestion_wizard() {
|
||||
sinon.stub(ChromeMigrationUtils, "getImportableLogins").resolves(["chrome"]);
|
||||
// Showing importables updates counts delayed, so adjust and cleanup.
|
||||
add_task(async function test_initialize() {
|
||||
const debounce = sinon
|
||||
.stub(LoginManagerParent, "SUGGEST_IMPORT_DEBOUNCE_MS")
|
||||
.value(0);
|
||||
const importable = sinon
|
||||
.stub(ChromeMigrationUtils, "getImportableLogins")
|
||||
.resolves(["chrome"]);
|
||||
|
||||
// This makes the third autocomplete test *not* show import suggestions.
|
||||
Services.prefs.setIntPref("signon.suggestImportCount", 2);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
debounce.restore();
|
||||
importable.restore();
|
||||
Services.prefs.clearUserPref("signon.suggestImportCount");
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function import_suggestion_wizard() {
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
|
@ -59,13 +76,9 @@ add_task(async function import_suggestion_wizard() {
|
|||
await BrowserTestUtils.closeWindow(wizard);
|
||||
}
|
||||
);
|
||||
|
||||
ChromeMigrationUtils.getImportableLogins.restore();
|
||||
});
|
||||
|
||||
add_task(async function import_suggestion_learn_more() {
|
||||
sinon.stub(ChromeMigrationUtils, "getImportableLogins").resolves(["chrome"]);
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
|
@ -98,6 +111,40 @@ add_task(async function import_suggestion_learn_more() {
|
|||
BrowserTestUtils.removeTab(supportTab);
|
||||
}
|
||||
);
|
||||
|
||||
ChromeMigrationUtils.getImportableLogins.restore();
|
||||
});
|
||||
|
||||
add_task(async function import_suggestion_not_shown() {
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: "https://example.com" + DIRECTORY_PATH + "form_basic.html",
|
||||
},
|
||||
async function(browser) {
|
||||
const popup = document.getElementById("PopupAutoComplete");
|
||||
ok(popup, "Got popup");
|
||||
let opened = false;
|
||||
openACPopup(popup, browser, "#form-basic-password").then(
|
||||
() => (opened = true)
|
||||
);
|
||||
|
||||
await TestUtils.waitForCondition(() => {
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown");
|
||||
return opened;
|
||||
});
|
||||
|
||||
const footer = popup.querySelector(`[originaltype="loginsFooter"]`);
|
||||
ok(footer, "Got footer richlistitem");
|
||||
|
||||
await TestUtils.waitForCondition(() => {
|
||||
return !EventUtils.isHidden(footer);
|
||||
}, "Waiting for footer to become visible");
|
||||
|
||||
ok(
|
||||
!popup.querySelector(`[originaltype="importableLogins"]`),
|
||||
"No importable suggestion shown"
|
||||
);
|
||||
|
||||
await closePopup(popup);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче