diff --git a/browser/extensions/formautofill/moz.build b/browser/extensions/formautofill/moz.build index a07bd452e4dab..0e33abf9149b0 100644 --- a/browser/extensions/formautofill/moz.build +++ b/browser/extensions/formautofill/moz.build @@ -33,6 +33,7 @@ elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows": ] BROWSER_CHROME_MANIFESTS += [ + "test/browser/address/browser.ini", "test/browser/browser.ini", "test/browser/creditCard/browser.ini", "test/browser/focus-leak/browser.ini", diff --git a/browser/extensions/formautofill/test/browser/address/browser.ini b/browser/extensions/formautofill/test/browser/address/browser.ini new file mode 100644 index 0000000000000..62f21dc47a128 --- /dev/null +++ b/browser/extensions/formautofill/test/browser/address/browser.ini @@ -0,0 +1,12 @@ +[DEFAULT] +prefs = + extensions.formautofill.addresses.enabled=true + # lower the interval for event telemetry in the content process to update the parent process + toolkit.telemetry.ipcBatchTimeout=0 +support-files = + ../head.js + ../../fixtures/autocomplete_address_basic.html + ../../fixtures/without_autocomplete_address_basic.html + head_address.js + +[browser_address_telemetry.js] diff --git a/browser/extensions/formautofill/test/browser/creditCard/browser_address_telemetry.js b/browser/extensions/formautofill/test/browser/address/browser_address_telemetry.js similarity index 74% rename from browser/extensions/formautofill/test/browser/creditCard/browser_address_telemetry.js rename to browser/extensions/formautofill/test/browser/address/browser_address_telemetry.js index cd5513ffe81ec..605718ae4893d 100644 --- a/browser/extensions/formautofill/test/browser/creditCard/browser_address_telemetry.js +++ b/browser/extensions/formautofill/test/browser/address/browser_address_telemetry.js @@ -1,7 +1,11 @@ "use strict"; -const { TelemetryTestUtils } = ChromeUtils.import( - "resource://testing-common/TelemetryTestUtils.jsm" +const { TelemetryTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/TelemetryTestUtils.sys.mjs" +); + +const { AddressTelemetry } = ChromeUtils.import( + "resource://autofill/AutofillTelemetry.jsm" ); // Preference definitions @@ -23,21 +27,21 @@ const HISTOGRAM_PROFILE_NUM_USES = "AUTOFILL_PROFILE_NUM_USES"; const HISTOGRAM_PROFILE_NUM_USES_KEY = "address"; // Autofill UI -const MANAGE_DIALOG_URL = MANAGE_ADDRESSES_DIALOG_URL; // MANAGE_CREDIT_CARDS_DIALOG_URL -const EDIT_DIALOG_URL = EDIT_ADDRESS_DIALOG_URL; // MANAGE_CREDIT_CARDS_DIALOG_URL +const MANAGE_DIALOG_URL = MANAGE_ADDRESSES_DIALOG_URL; +const EDIT_DIALOG_URL = EDIT_ADDRESS_DIALOG_URL; const DIALOG_SIZE = "width=600,height=400"; -const MANAGE_RECORD_SELECTOR = "#addresses"; // "#credit-cards"; +const MANAGE_RECORD_SELECTOR = "#addresses"; // Test specific definitions -const TEST_PROFILE = TEST_ADDRESS_1; // TEST_CREDIT_CARD_1 -const TEST_PROFILE_1 = TEST_ADDRESS_1; // TEST_CREDIT_CARD_1 -const TEST_PROFILE_2 = TEST_ADDRESS_2; // TEST_CREDIT_CARD_1 -const TEST_PROFILE_3 = TEST_ADDRESS_3; // TEST_CREDIT_CARD_1 -const TEST_BASIC_AUTOFILL_FORM_URL = ADDRESS_FORM_URL; // CREDITCARD_FORM_URL -const TEST_WITHOUT_AUTOCOMPLETE_URL = ADDRESS_FORM_WITHOUT_AUTOCOMPLETE_URL; -const TEST_FOCUS_FIELD = "given-name"; -const TEST_FOCUS_SELECTOR = "#" + TEST_FOCUS_FIELD; // "#cc-number" +const TEST_PROFILE = TEST_ADDRESS_1; +const TEST_PROFILE_1 = TEST_ADDRESS_1; +const TEST_PROFILE_2 = TEST_ADDRESS_2; +const TEST_PROFILE_3 = TEST_ADDRESS_3; + +const TEST_FOCUS_NAME_FIELD = "given-name"; +const TEST_FOCUS_NAME_FIELD_SELECTOR = "#" + TEST_FOCUS_NAME_FIELD; +// Used for tests that update address fields after filling const TEST_NEW_VALUES = { "#given-name": "Test User", "#organization": "Sesame Street", @@ -45,6 +49,77 @@ const TEST_NEW_VALUES = { "#tel": "1-345-345-3456", }; +const TEST_BASIC_ADDRESS_FORM_URL = ADDRESS_FORM_URL; +const TEST_BASIC_ADDRESS_FORM_WITHOUT_AC_URL = ADDRESS_FORM_WITHOUT_AUTOCOMPLETE_URL; +// This should be sync with the address fields that appear in TEST_BASIC_ADDRESS_FORM +const TEST_BASIC_ADDRESS_FORM_FIELDS = [ + "street_address", + "address_level1", + "address_level2", + "postal_code", + "country", + "given_name", + "family_name", + "organization", + "email", + "tel", +]; + +function buildFormExtra(list, fields, fieldValue, defaultValue, aExtra = {}) { + let extra = {}; + for (const field of list) { + if (aExtra[field]) { + extra[field] = aExtra[field]; + } else { + extra[field] = fields.includes(field) ? fieldValue : defaultValue; + } + } + return extra; +} + +/** + * Utility function to generate expected value for `address_form` and `address_form_ext` + * telemetry event. + * + * @param {string} method see `methods` in `address_form` event telemetry + * @param {object} defaultExtra default extra object, this will not be overwritten + * @param {object} fields address fields that will be set to `value` param + * @param {string} value value to set for fields list in `fields` argument + * @param {string} defaultValue value to set for address fields that are not listed in `fields` argument` + */ +function formArgs( + method, + defaultExtra, + fields = [], + value = undefined, + defaultValue = null +) { + if (["popup_shown", "filled_modified"].includes(method)) { + return [["address", method, "address_form", undefined, defaultExtra]]; + } + let extra = buildFormExtra( + AddressTelemetry.SUPPORTED_FIELDS_IN_FORM, + fields, + value, + defaultValue, + defaultExtra + ); + + let extraExt = buildFormExtra( + AddressTelemetry.SUPPORTED_FIELDS_IN_FORM_EXT, + fields, + value, + defaultValue, + defaultExtra + ); + + // The order here should sync with AutofillTelemetry. + return [ + ["address", method, "address_form", undefined, extra], + ["address", method, "address_form_ext", undefined, extraExt], + ]; +} + function getProfiles() { return getAddresses(); } @@ -145,11 +220,11 @@ async function openTabAndUseAutofillProfile( ) { let tab = await BrowserTestUtils.openNewForegroundTab( gBrowser, - TEST_BASIC_AUTOFILL_FORM_URL + TEST_BASIC_ADDRESS_FORM_URL ); let browser = tab.linkedBrowser; - await openPopupOn(browser, "form " + TEST_FOCUS_SELECTOR); + await openPopupOn(browser, "form " + TEST_FOCUS_NAME_FIELD_SELECTOR); for (let i = 0; i <= idx; i++) { await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser); @@ -158,13 +233,13 @@ async function openTabAndUseAutofillProfile( await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser); await waitForAutofill( browser, - TEST_FOCUS_SELECTOR, - profile[TEST_FOCUS_FIELD] + TEST_FOCUS_NAME_FIELD_SELECTOR, + profile[TEST_FOCUS_NAME_FIELD] ); await focusUpdateSubmitForm( browser, { - focusSelector: TEST_FOCUS_SELECTOR, + focusSelector: TEST_FOCUS_NAME_FIELD_SELECTOR, newValues: {}, }, submitForm @@ -201,9 +276,9 @@ add_task(async function test_popup_opened() { await setStorage(TEST_PROFILE); await BrowserTestUtils.withNewTab( - { gBrowser, url: TEST_BASIC_AUTOFILL_FORM_URL }, + { gBrowser, url: TEST_BASIC_ADDRESS_FORM_URL }, async function(browser) { - const focusInput = TEST_FOCUS_SELECTOR; + const focusInput = TEST_FOCUS_NAME_FIELD_SELECTOR; await openPopupOn(browser, focusInput); @@ -212,8 +287,10 @@ add_task(async function test_popup_opened() { } ); + const fields = TEST_BASIC_ADDRESS_FORM_FIELDS; await assertTelemetry([ - // TODO: Implement form interaction event telemetry + ...formArgs("detected", {}, fields, "true", "false"), + ...formArgs("popup_shown", { field_name: TEST_FOCUS_NAME_FIELD }), ]); TelemetryTestUtils.assertScalar( @@ -237,16 +314,18 @@ add_task(async function test_popup_opened_form_without_autocomplete() { await setStorage(TEST_PROFILE); await BrowserTestUtils.withNewTab( - { gBrowser, url: TEST_WITHOUT_AUTOCOMPLETE_URL }, + { gBrowser, url: TEST_BASIC_ADDRESS_FORM_WITHOUT_AC_URL }, async function(browser) { - const focusInput = TEST_FOCUS_SELECTOR; + const focusInput = TEST_FOCUS_NAME_FIELD_SELECTOR; await openPopupOn(browser, focusInput); await closePopup(browser); } ); + const fields = TEST_BASIC_ADDRESS_FORM_FIELDS; await assertTelemetry([ - //TODO: Implement form interaction event telemetry + ...formArgs("detected", {}, fields, "0", "false"), + ...formArgs("popup_shown", { field_name: TEST_FOCUS_NAME_FIELD }), ]); TelemetryTestUtils.assertScalar( @@ -276,7 +355,7 @@ add_task(async function test_submit_autofill_profile_new() { expectChanged = undefined ) { await BrowserTestUtils.withNewTab( - { gBrowser, url: TEST_BASIC_AUTOFILL_FORM_URL }, + { gBrowser, url: TEST_BASIC_ADDRESS_FORM_URL }, async function(browser) { let onPopupShown = waitForPopupShown(); let onChanged; @@ -285,7 +364,7 @@ add_task(async function test_submit_autofill_profile_new() { } await focusUpdateSubmitForm(browser, { - focusSelector: TEST_FOCUS_SELECTOR, + focusSelector: TEST_FOCUS_NAME_FIELD_SELECTOR, newValues: TEST_NEW_VALUES, }); @@ -316,8 +395,10 @@ add_task(async function test_submit_autofill_profile_new() { Services.telemetry.clearScalars(); Services.telemetry.getKeyedHistogramById(HISTOGRAM_PROFILE_NUM_USES).clear(); + const fields = TEST_BASIC_ADDRESS_FORM_FIELDS; let expected_content = [ - // TODO: Implement form interaction event telemetry + ...formArgs("detected", {}, fields, "true", "false"), + ...formArgs("submitted", {}, fields, "user_filled", "unavailable"), ]; // FTU @@ -360,7 +441,7 @@ add_task(async function test_submit_autofill_profile_update() { Assert.equal(profiles.length, 1, "1 entry in storage"); await BrowserTestUtils.withNewTab( - { gBrowser, url: TEST_BASIC_AUTOFILL_FORM_URL }, + { gBrowser, url: TEST_BASIC_ADDRESS_FORM_URL }, async function(browser) { let onPopupShown = waitForPopupShown(); let onChanged; @@ -368,17 +449,17 @@ add_task(async function test_submit_autofill_profile_update() { onChanged = TestUtils.topicObserved("formautofill-storage-changed"); } - await openPopupOn(browser, TEST_FOCUS_SELECTOR); + await openPopupOn(browser, TEST_FOCUS_NAME_FIELD_SELECTOR); await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser); await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser); await waitForAutofill( browser, - TEST_FOCUS_SELECTOR, - TEST_PROFILE[TEST_FOCUS_FIELD] + TEST_FOCUS_NAME_FIELD_SELECTOR, + TEST_PROFILE[TEST_FOCUS_NAME_FIELD] ); await focusUpdateSubmitForm(browser, { - focusSelector: TEST_FOCUS_SELECTOR, + focusSelector: TEST_FOCUS_NAME_FIELD_SELECTOR, newValues: TEST_NEW_VALUES, }); await onPopupShown; @@ -409,7 +490,28 @@ add_task(async function test_submit_autofill_profile_update() { Services.telemetry.clearScalars(); Services.telemetry.getKeyedHistogramById(HISTOGRAM_PROFILE_NUM_USES).clear(); - let expected_content = []; + const fields = TEST_BASIC_ADDRESS_FORM_FIELDS; + let expected_content = [ + ...formArgs("detected", {}, fields, "true", "false"), + ...formArgs("popup_shown", { field_name: TEST_FOCUS_NAME_FIELD }), + ...formArgs("filled", {}, fields, "filled", "unavailable"), + ...formArgs("filled_modified", { field_name: "given-name" }), + ...formArgs("filled_modified", { field_name: "organization" }), + ...formArgs("filled_modified", { field_name: "street-address" }), + ...formArgs("filled_modified", { field_name: "tel" }), + ...formArgs( + "submitted", + { + given_name: "user_filled", + organization: "user_filled", + street_address: "user_filled", + tel: "user_filled", + }, + fields, + "autofilled", + "unavailable" + ), + ]; await test_per_command(MAIN_BUTTON, undefined, { 1: 1 }, 1); await assertTelemetry(expected_content, [ @@ -573,6 +675,7 @@ add_task(async function test_histogram() { }); add_task(async function test_clear_autofill_profile_autofill() { - // TODO: Support field detection telemetry + // Address does not have clear pref. Keep the test so we know we should implement + // the test if we support clearing address via autocomplete. Assert.ok(true); }); diff --git a/browser/extensions/formautofill/test/browser/address/head_address.js b/browser/extensions/formautofill/test/browser/address/head_address.js new file mode 100644 index 0000000000000..42196e8422691 --- /dev/null +++ b/browser/extensions/formautofill/test/browser/address/head_address.js @@ -0,0 +1 @@ +/* import-globals-from ../head.js */ diff --git a/browser/extensions/formautofill/test/browser/creditCard/browser.ini b/browser/extensions/formautofill/test/browser/creditCard/browser.ini index afed5f5e9219b..b1d169b9f1295 100644 --- a/browser/extensions/formautofill/test/browser/creditCard/browser.ini +++ b/browser/extensions/formautofill/test/browser/creditCard/browser.ini @@ -7,16 +7,12 @@ prefs = support-files = ../head.js !/browser/extensions/formautofill/test/fixtures/autocomplete_basic.html - ../../fixtures/autocomplete_address_basic.html ../../fixtures/autocomplete_creditcard_basic.html ../../fixtures/autocomplete_creditcard_iframe.html ../../fixtures/autocomplete_creditcard_cc_exp_field.html - ../../fixtures/without_autocomplete_address_basic.html ../../fixtures/without_autocomplete_creditcard_basic.html head_cc.js -[browser_address_telemetry.js] -skip-if = apple_silicon && !debug # Bug 1714221 [browser_creditCard_doorhanger.js] skip-if = (!debug && os == "mac") || (os == "win" && ccov) # perma-fail see Bug 1655601, Bug 1655600 [browser_creditCard_dropdown_layout.js] diff --git a/browser/extensions/formautofill/test/browser/head.js b/browser/extensions/formautofill/test/browser/head.js index a0da7fbc192af..4b7d65f388eba 100644 --- a/browser/extensions/formautofill/test/browser/head.js +++ b/browser/extensions/formautofill/test/browser/head.js @@ -27,7 +27,11 @@ const FORM_URL = BASE_URL + "autocomplete_basic.html"; const ADDRESS_FORM_URL = "https://example.org" + HTTP_TEST_PATH + - "creditCard/autocomplete_address_basic.html"; + "address/autocomplete_address_basic.html"; +const ADDRESS_FORM_WITHOUT_AUTOCOMPLETE_URL = + "https://example.org" + + HTTP_TEST_PATH + + "address/without_autocomplete_address_basic.html"; const CREDITCARD_FORM_URL = "https://example.org" + HTTP_TEST_PATH + @@ -40,10 +44,6 @@ const CREDITCARD_FORM_COMBINED_EXPIRY_URL = "https://example.org" + HTTP_TEST_PATH + "creditCard/autocomplete_creditcard_cc_exp_field.html"; -const ADDRESS_FORM_WITHOUT_AUTOCOMPLETE_URL = - "https://example.org" + - HTTP_TEST_PATH + - "creditCard/without_autocomplete_address_basic.html"; const CREDITCARD_FORM_WITHOUT_AUTOCOMPLETE_URL = "https://example.org" + HTTP_TEST_PATH + diff --git a/toolkit/components/formautofill/AutofillTelemetry.jsm b/toolkit/components/formautofill/AutofillTelemetry.jsm index dbd0ad4f5edd5..0639a53896112 100644 --- a/toolkit/components/formautofill/AutofillTelemetry.jsm +++ b/toolkit/components/formautofill/AutofillTelemetry.jsm @@ -4,7 +4,7 @@ "use strict"; -var EXPORTED_SYMBOLS = ["AutofillTelemetry"]; +var EXPORTED_SYMBOLS = ["AutofillTelemetry", "AddressTelemetry"]; const { FormAutofillUtils } = ChromeUtils.import( "resource://autofill/FormAutofillUtils.jsm" @@ -38,6 +38,10 @@ class AutofillTelemetryBase { } #setFormEventExtra(extra, key, value) { + if (!this.SUPPORTED_FIELDS[key]) { + return; + } + extra[this.SUPPORTED_FIELDS[key]] = value; } @@ -207,6 +211,8 @@ class AutofillTelemetryBase { class AddressTelemetry extends AutofillTelemetryBase { EVENT_CATEGORY = "address"; + EVENT_OBJECT_FORM_INTERACTION = "address_form"; + EVENT_OBJECT_FORM_INTERACTION_EXT = "address_form_ext"; SCALAR_DETECTED_SECTION_COUNT = "formautofill.addresses.detected_sections_count"; @@ -217,6 +223,78 @@ class AddressTelemetry extends AutofillTelemetryBase { HISTOGRAM_PROFILE_NUM_USES = "AUTOFILL_PROFILE_NUM_USES"; HISTOGRAM_PROFILE_NUM_USES_KEY = "address"; + + // Fields that are record in `address_form` and `address_form_ext` telemetry + SUPPORTED_FIELDS = { + "street-address": "street_address", + "address-line1": "address_line1", + "address-line2": "address_line2", + "address-line3": "address_line3", + "address-level1": "address_level1", + "address-level2": "address_level2", + "postal-code": "postal_code", + country: "country", + name: "name", + "given-name": "given_name", + "additional-name": "additional_name", + "family-name": "family_name", + email: "email", + organization: "organization", + tel: "tel", + }; + + // Fields that are record in `address_form` event telemetry extra_keys + static SUPPORTED_FIELDS_IN_FORM = [ + "street_address", + "address_line1", + "address_line2", + "address_line3", + "address_level2", + "address_level1", + "postal_code", + "country", + ]; + + // Fields that are record in `address_form_ext` event telemetry extra_keys + static SUPPORTED_FIELDS_IN_FORM_EXT = [ + "name", + "given_name", + "additional_name", + "family_name", + "email", + "organization", + "tel", + ]; + + recordFormEvent(method, flowId, extra) { + let extExtra = {}; + if (["detected", "filled", "submitted"].includes(method)) { + for (const [key, value] of Object.entries(extra)) { + if (AddressTelemetry.SUPPORTED_FIELDS_IN_FORM_EXT.includes(key)) { + extExtra[key] = value; + delete extra[key]; + } + } + } + + Services.telemetry.recordEvent( + this.EVENT_CATEGORY, + method, + this.EVENT_OBJECT_FORM_INTERACTION, + flowId, + extra + ); + + if (Object.keys(extExtra).length) { + Services.telemetry.recordEvent( + this.EVENT_CATEGORY, + method, + this.EVENT_OBJECT_FORM_INTERACTION_EXT, + flowId, + extExtra + ); + } + } } class CreditCardTelemetry extends AutofillTelemetryBase { diff --git a/toolkit/components/formautofill/FormAutofillContent.jsm b/toolkit/components/formautofill/FormAutofillContent.jsm index d46b773f46daa..d7f76628fe65e 100644 --- a/toolkit/components/formautofill/FormAutofillContent.jsm +++ b/toolkit/components/formautofill/FormAutofillContent.jsm @@ -857,13 +857,11 @@ var FormAutofillContent = { ); let fieldName = FormAutofillContent.activeFieldDetail?.fieldName; - if (lazy.FormAutofillUtils.isCreditCardField(fieldName)) { - lazy.AutofillTelemetry.recordFormInteractionEvent( - "popup_shown", - this.activeSection, - { fieldName } - ); - } + lazy.AutofillTelemetry.recordFormInteractionEvent( + "popup_shown", + this.activeSection, + { fieldName } + ); }, _markAsAutofillField(field) { diff --git a/toolkit/components/formautofill/FormAutofillHandler.jsm b/toolkit/components/formautofill/FormAutofillHandler.jsm index eecf05f39a9b9..52643e0981f7e 100644 --- a/toolkit/components/formautofill/FormAutofillHandler.jsm +++ b/toolkit/components/formautofill/FormAutofillHandler.jsm @@ -701,15 +701,13 @@ class FormAutofillSection { this._changeFieldState(targetFieldDetail, FIELD_STATES.NORMAL); - if (isCreditCardField) { - lazy.AutofillTelemetry.recordFormInteractionEvent( - "filled_modified", - this, - { - fieldName: targetFieldDetail.fieldName, - } - ); - } + lazy.AutofillTelemetry.recordFormInteractionEvent( + "filled_modified", + this, + { + fieldName: targetFieldDetail.fieldName, + } + ); let isAutofilled = false; let dimFieldDetails = []; diff --git a/toolkit/components/telemetry/Events.yaml b/toolkit/components/telemetry/Events.yaml index 8d17e63066ae5..b5b63356d3de2 100644 --- a/toolkit/components/telemetry/Events.yaml +++ b/toolkit/components/telemetry/Events.yaml @@ -559,6 +559,63 @@ address: - "firefox" record_in_processes: ["main"] release_channel_collection: opt-out + address_form: + description: >- + User interactions for address autofill forms + 'detected': Recorded when a form is recognized as a credit card form. + The possible value of cc_* in extra_keys are "true", "false", or 0 + When the value is "true", the field is identified via autocomplete attribute + When the value is "false", the field is not detected in the form + When the value is an 0, then the field is identified by regexp-based heuristic + 'popup_shown': Recorded when autofill popup is shown. Using field_name to record the field + that triggers this event + 'filled': Recorded when a form is autofiled. Possible values are + `filled`, `not_filled`, `user_filled` or `unavailable` + 'filled_modified': Recorded when a field is autofilled and then modified by the user. + Using field_name to record the field that triggers this event. + 'submitted': Recorded when a form is submitted. Possible values are `autofilled`, `user_filled` or `unavailable` + 'cleared' Recorded when a form is cleared . Using field_name to record the field that triggers this event + objects: ["address_form"] + methods: ["detected", "popup_shown", "filled", "filled_modified", "submitted", "cleared"] + bug_numbers: [1804901] + notification_emails: ["autofill@lists.mozilla.org", "passwords-dev@mozilla.org"] + expiry_version: never + products: + - "firefox" + record_in_processes: ["content"] + release_channel_collection: opt-out + extra_keys: + street_address: street address result, filled when method is `detected`, `filled`, or `filled_modified` + address_line1: address_line1 result, filled when method is `detected`, `filled`, or `filled_modified`. + address_line2: address_line2 result, filled when method is `detected`, `filled`, or `filled_modified`. + address_line3: address_line3 result, filled when method is `detected`, `filled`, or `filled_modified`. + address_level1: address_level1 result, filled when method is `detected`, `filled`, or `filled_modified`. + address_level2: address_level2 result, filled when method is `detected`, `filled`, or `filled_modified`. + postal_code: postal_code result, filled when method is `detected`, `filled`, or `filled_modified`. + country: country result, filled when method is `detected`, `filled`, or `filled_modified`. + field_name: Name of the field being affected by the method, filled when method is `popup_shown` or `filled_modified`. + address_form_ext: + description: >- + Address has too many fields so we cannot cover them all in the above `address_form` telemetry + This telemetry is used to record address fields that are not listed in `address_form` + objects: ["address_form_ext"] + methods: ["detected", "filled", "submitted"] + bug_numbers: [1804901] + notification_emails: ["autofill@lists.mozilla.org", "passwords-dev@mozilla.org"] + expiry_version: never + products: + - "firefox" + record_in_processes: ["content"] + release_channel_collection: opt-out + extra_keys: + name: name + given_name: give_name + additional_name: additional_name + family_name: family_name + email: email + organization: organization + tel: telephone + creditcard: doorhanger: description: >-